aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric Dumazet <eric.dumazet@gmail.com>2012-01-31 00:18:33 -0500
committerDavid S. Miller <davem@davemloft.net>2012-01-31 12:14:00 -0500
commita915da9b69273815527ccb3789421cb7027b545b (patch)
tree79b266da33febc50bc54adc033ac9e38a1750bcf
parenta2d91241a80ec9bbc5ab24b9a2c4d730b3fa5730 (diff)
tcp: md5: rcu conversion
In order to be able to support proper RST messages for TCP MD5 flows, we need to allow access to MD5 keys without locking listener socket. This conversion is a nice cleanup, and shrinks size of timewait sockets by 80 bytes. IPv6 code reuses generic code found in IPv4 instead of duplicating it. Control path uses GFP_KERNEL allocations instead of GFP_ATOMIC. Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com> Cc: Shawn Lu <shawn.lu@ericsson.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/linux/tcp.h3
-rw-r--r--include/net/tcp.h61
-rw-r--r--net/ipv4/tcp_ipv4.c227
-rw-r--r--net/ipv4/tcp_minisocks.c12
-rw-r--r--net/ipv6/tcp_ipv6.c173
5 files changed, 141 insertions, 335 deletions
diff --git a/include/linux/tcp.h b/include/linux/tcp.h
index 46a85c9e1f25..c2025f159641 100644
--- a/include/linux/tcp.h
+++ b/include/linux/tcp.h
@@ -486,8 +486,7 @@ struct tcp_timewait_sock {
486 u32 tw_ts_recent; 486 u32 tw_ts_recent;
487 long tw_ts_recent_stamp; 487 long tw_ts_recent_stamp;
488#ifdef CONFIG_TCP_MD5SIG 488#ifdef CONFIG_TCP_MD5SIG
489 u16 tw_md5_keylen; 489 struct tcp_md5sig_key *tw_md5_key;
490 u8 tw_md5_key[TCP_MD5SIG_MAXKEYLEN];
491#endif 490#endif
492 /* Few sockets in timewait have cookies; in that case, then this 491 /* Few sockets in timewait have cookies; in that case, then this
493 * object holds a reference to them (tw_cookie_values->kref). 492 * object holds a reference to them (tw_cookie_values->kref).
diff --git a/include/net/tcp.h b/include/net/tcp.h
index 3c903462adf5..10ae4c7b6b4f 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -1130,35 +1130,26 @@ static inline void tcp_clear_all_retrans_hints(struct tcp_sock *tp)
1130/* MD5 Signature */ 1130/* MD5 Signature */
1131struct crypto_hash; 1131struct crypto_hash;
1132 1132
1133union tcp_md5_addr {
1134 struct in_addr a4;
1135#if IS_ENABLED(CONFIG_IPV6)
1136 struct in6_addr a6;
1137#endif
1138};
1139
1133/* - key database */ 1140/* - key database */
1134struct tcp_md5sig_key { 1141struct tcp_md5sig_key {
1135 u8 *key; 1142 struct hlist_node node;
1136 u8 keylen; 1143 u8 keylen;
1137}; 1144 u8 family; /* AF_INET or AF_INET6 */
1138 1145 union tcp_md5_addr addr;
1139struct tcp4_md5sig_key { 1146 u8 key[TCP_MD5SIG_MAXKEYLEN];
1140 struct tcp_md5sig_key base; 1147 struct rcu_head rcu;
1141 __be32 addr;
1142};
1143
1144struct tcp6_md5sig_key {
1145 struct tcp_md5sig_key base;
1146#if 0
1147 u32 scope_id; /* XXX */
1148#endif
1149 struct in6_addr addr;
1150}; 1148};
1151 1149
1152/* - sock block */ 1150/* - sock block */
1153struct tcp_md5sig_info { 1151struct tcp_md5sig_info {
1154 struct tcp4_md5sig_key *keys4; 1152 struct hlist_head head;
1155#if IS_ENABLED(CONFIG_IPV6)
1156 struct tcp6_md5sig_key *keys6;
1157 u32 entries6;
1158 u32 alloced6;
1159#endif
1160 u32 entries4;
1161 u32 alloced4;
1162}; 1153};
1163 1154
1164/* - pseudo header */ 1155/* - pseudo header */
@@ -1195,19 +1186,25 @@ extern int tcp_v4_md5_hash_skb(char *md5_hash, struct tcp_md5sig_key *key,
1195 const struct sock *sk, 1186 const struct sock *sk,
1196 const struct request_sock *req, 1187 const struct request_sock *req,
1197 const struct sk_buff *skb); 1188 const struct sk_buff *skb);
1198extern struct tcp_md5sig_key * tcp_v4_md5_lookup(struct sock *sk, 1189extern int tcp_md5_do_add(struct sock *sk, const union tcp_md5_addr *addr,
1199 struct sock *addr_sk); 1190 int family, const u8 *newkey,
1200extern int tcp_v4_md5_do_add(struct sock *sk, __be32 addr, u8 *newkey, 1191 u8 newkeylen, gfp_t gfp);
1201 u8 newkeylen); 1192extern int tcp_md5_do_del(struct sock *sk, const union tcp_md5_addr *addr,
1202extern int tcp_v4_md5_do_del(struct sock *sk, __be32 addr); 1193 int family);
1194extern struct tcp_md5sig_key *tcp_v4_md5_lookup(struct sock *sk,
1195 struct sock *addr_sk);
1203 1196
1204#ifdef CONFIG_TCP_MD5SIG 1197#ifdef CONFIG_TCP_MD5SIG
1205#define tcp_twsk_md5_key(twsk) ((twsk)->tw_md5_keylen ? \ 1198extern struct tcp_md5sig_key *tcp_md5_do_lookup(struct sock *sk,
1206 &(struct tcp_md5sig_key) { \ 1199 const union tcp_md5_addr *addr, int family);
1207 .key = (twsk)->tw_md5_key, \ 1200#define tcp_twsk_md5_key(twsk) ((twsk)->tw_md5_key)
1208 .keylen = (twsk)->tw_md5_keylen, \
1209 } : NULL)
1210#else 1201#else
1202static inline struct tcp_md5sig_key *tcp_md5_do_lookup(struct sock *sk,
1203 const union tcp_md5_addr *addr,
1204 int family)
1205{
1206 return NULL;
1207}
1211#define tcp_twsk_md5_key(twsk) NULL 1208#define tcp_twsk_md5_key(twsk) NULL
1212#endif 1209#endif
1213 1210
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index 345e24928fa6..1d5fd82c5c08 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -90,16 +90,8 @@ EXPORT_SYMBOL(sysctl_tcp_low_latency);
90 90
91 91
92#ifdef CONFIG_TCP_MD5SIG 92#ifdef CONFIG_TCP_MD5SIG
93static struct tcp_md5sig_key *tcp_v4_md5_do_lookup(struct sock *sk, 93static int tcp_v4_md5_hash_hdr(char *md5_hash, const struct tcp_md5sig_key *key,
94 __be32 addr);
95static int tcp_v4_md5_hash_hdr(char *md5_hash, struct tcp_md5sig_key *key,
96 __be32 daddr, __be32 saddr, const struct tcphdr *th); 94 __be32 daddr, __be32 saddr, const struct tcphdr *th);
97#else
98static inline
99struct tcp_md5sig_key *tcp_v4_md5_do_lookup(struct sock *sk, __be32 addr)
100{
101 return NULL;
102}
103#endif 95#endif
104 96
105struct inet_hashinfo tcp_hashinfo; 97struct inet_hashinfo tcp_hashinfo;
@@ -631,7 +623,9 @@ static void tcp_v4_send_reset(struct sock *sk, struct sk_buff *skb)
631 arg.iov[0].iov_len = sizeof(rep.th); 623 arg.iov[0].iov_len = sizeof(rep.th);
632 624
633#ifdef CONFIG_TCP_MD5SIG 625#ifdef CONFIG_TCP_MD5SIG
634 key = sk ? tcp_v4_md5_do_lookup(sk, ip_hdr(skb)->saddr) : NULL; 626 key = sk ? tcp_md5_do_lookup(sk,
627 (union tcp_md5_addr *)&ip_hdr(skb)->saddr,
628 AF_INET) : NULL;
635 if (key) { 629 if (key) {
636 rep.opt[0] = htonl((TCPOPT_NOP << 24) | 630 rep.opt[0] = htonl((TCPOPT_NOP << 24) |
637 (TCPOPT_NOP << 16) | 631 (TCPOPT_NOP << 16) |
@@ -759,7 +753,8 @@ static void tcp_v4_reqsk_send_ack(struct sock *sk, struct sk_buff *skb,
759 tcp_rsk(req)->rcv_isn + 1, req->rcv_wnd, 753 tcp_rsk(req)->rcv_isn + 1, req->rcv_wnd,
760 req->ts_recent, 754 req->ts_recent,
761 0, 755 0,
762 tcp_v4_md5_do_lookup(sk, ip_hdr(skb)->daddr), 756 tcp_md5_do_lookup(sk, (union tcp_md5_addr *)&ip_hdr(skb)->daddr,
757 AF_INET),
763 inet_rsk(req)->no_srccheck ? IP_REPLY_ARG_NOSRCCHECK : 0, 758 inet_rsk(req)->no_srccheck ? IP_REPLY_ARG_NOSRCCHECK : 0,
764 ip_hdr(skb)->tos); 759 ip_hdr(skb)->tos);
765} 760}
@@ -876,146 +871,124 @@ static struct ip_options_rcu *tcp_v4_save_options(struct sock *sk,
876 */ 871 */
877 872
878/* Find the Key structure for an address. */ 873/* Find the Key structure for an address. */
879static struct tcp_md5sig_key * 874struct tcp_md5sig_key *tcp_md5_do_lookup(struct sock *sk,
880 tcp_v4_md5_do_lookup(struct sock *sk, __be32 addr) 875 const union tcp_md5_addr *addr,
876 int family)
881{ 877{
882 struct tcp_sock *tp = tcp_sk(sk); 878 struct tcp_sock *tp = tcp_sk(sk);
883 int i; 879 struct tcp_md5sig_key *key;
880 struct hlist_node *pos;
881 unsigned int size = sizeof(struct in_addr);
884 882
885 if (!tp->md5sig_info || !tp->md5sig_info->entries4) 883 if (!tp->md5sig_info)
886 return NULL; 884 return NULL;
887 for (i = 0; i < tp->md5sig_info->entries4; i++) { 885#if IS_ENABLED(CONFIG_IPV6)
888 if (tp->md5sig_info->keys4[i].addr == addr) 886 if (family == AF_INET6)
889 return &tp->md5sig_info->keys4[i].base; 887 size = sizeof(struct in6_addr);
888#endif
889 hlist_for_each_entry_rcu(key, pos, &tp->md5sig_info->head, node) {
890 if (key->family != family)
891 continue;
892 if (!memcmp(&key->addr, addr, size))
893 return key;
890 } 894 }
891 return NULL; 895 return NULL;
892} 896}
897EXPORT_SYMBOL(tcp_md5_do_lookup);
893 898
894struct tcp_md5sig_key *tcp_v4_md5_lookup(struct sock *sk, 899struct tcp_md5sig_key *tcp_v4_md5_lookup(struct sock *sk,
895 struct sock *addr_sk) 900 struct sock *addr_sk)
896{ 901{
897 return tcp_v4_md5_do_lookup(sk, inet_sk(addr_sk)->inet_daddr); 902 union tcp_md5_addr *addr;
903
904 addr = (union tcp_md5_addr *)&inet_sk(addr_sk)->inet_daddr;
905 return tcp_md5_do_lookup(sk, addr, AF_INET);
898} 906}
899EXPORT_SYMBOL(tcp_v4_md5_lookup); 907EXPORT_SYMBOL(tcp_v4_md5_lookup);
900 908
901static struct tcp_md5sig_key *tcp_v4_reqsk_md5_lookup(struct sock *sk, 909static struct tcp_md5sig_key *tcp_v4_reqsk_md5_lookup(struct sock *sk,
902 struct request_sock *req) 910 struct request_sock *req)
903{ 911{
904 return tcp_v4_md5_do_lookup(sk, inet_rsk(req)->rmt_addr); 912 union tcp_md5_addr *addr;
913
914 addr = (union tcp_md5_addr *)&inet_rsk(req)->rmt_addr;
915 return tcp_md5_do_lookup(sk, addr, AF_INET);
905} 916}
906 917
907/* This can be called on a newly created socket, from other files */ 918/* This can be called on a newly created socket, from other files */
908int tcp_v4_md5_do_add(struct sock *sk, __be32 addr, 919int tcp_md5_do_add(struct sock *sk, const union tcp_md5_addr *addr,
909 u8 *newkey, u8 newkeylen) 920 int family, const u8 *newkey, u8 newkeylen, gfp_t gfp)
910{ 921{
911 /* Add Key to the list */ 922 /* Add Key to the list */
912 struct tcp_md5sig_key *key; 923 struct tcp_md5sig_key *key;
913 struct tcp_sock *tp = tcp_sk(sk); 924 struct tcp_sock *tp = tcp_sk(sk);
914 struct tcp4_md5sig_key *keys; 925 struct tcp_md5sig_info *md5sig;
915 926
916 key = tcp_v4_md5_do_lookup(sk, addr); 927 key = tcp_md5_do_lookup(sk, (union tcp_md5_addr *)&addr, AF_INET);
917 if (key) { 928 if (key) {
918 /* Pre-existing entry - just update that one. */ 929 /* Pre-existing entry - just update that one. */
919 kfree(key->key); 930 memcpy(key->key, newkey, newkeylen);
920 key->key = newkey;
921 key->keylen = newkeylen; 931 key->keylen = newkeylen;
922 } else { 932 return 0;
923 struct tcp_md5sig_info *md5sig; 933 }
924
925 if (!tp->md5sig_info) {
926 tp->md5sig_info = kzalloc(sizeof(*tp->md5sig_info),
927 GFP_ATOMIC);
928 if (!tp->md5sig_info) {
929 kfree(newkey);
930 return -ENOMEM;
931 }
932 sk_nocaps_add(sk, NETIF_F_GSO_MASK);
933 }
934 934
935 md5sig = tp->md5sig_info; 935 md5sig = tp->md5sig_info;
936 if (md5sig->entries4 == 0 && 936 if (!md5sig) {
937 tcp_alloc_md5sig_pool(sk) == NULL) { 937 md5sig = kmalloc(sizeof(*md5sig), gfp);
938 kfree(newkey); 938 if (!md5sig)
939 return -ENOMEM; 939 return -ENOMEM;
940 }
941
942 if (md5sig->alloced4 == md5sig->entries4) {
943 keys = kmalloc((sizeof(*keys) *
944 (md5sig->entries4 + 1)), GFP_ATOMIC);
945 if (!keys) {
946 kfree(newkey);
947 if (md5sig->entries4 == 0)
948 tcp_free_md5sig_pool();
949 return -ENOMEM;
950 }
951 940
952 if (md5sig->entries4) 941 sk_nocaps_add(sk, NETIF_F_GSO_MASK);
953 memcpy(keys, md5sig->keys4, 942 INIT_HLIST_HEAD(&md5sig->head);
954 sizeof(*keys) * md5sig->entries4); 943 tp->md5sig_info = md5sig;
944 }
955 945
956 /* Free old key list, and reference new one */ 946 key = kmalloc(sizeof(*key), gfp);
957 kfree(md5sig->keys4); 947 if (!key)
958 md5sig->keys4 = keys; 948 return -ENOMEM;
959 md5sig->alloced4++; 949 if (hlist_empty(&md5sig->head) && !tcp_alloc_md5sig_pool(sk)) {
960 } 950 kfree(key);
961 md5sig->entries4++; 951 return -ENOMEM;
962 md5sig->keys4[md5sig->entries4 - 1].addr = addr;
963 md5sig->keys4[md5sig->entries4 - 1].base.key = newkey;
964 md5sig->keys4[md5sig->entries4 - 1].base.keylen = newkeylen;
965 } 952 }
953
954 memcpy(key->key, newkey, newkeylen);
955 key->keylen = newkeylen;
956 key->family = family;
957 memcpy(&key->addr, addr,
958 (family == AF_INET6) ? sizeof(struct in6_addr) :
959 sizeof(struct in_addr));
960 hlist_add_head_rcu(&key->node, &md5sig->head);
966 return 0; 961 return 0;
967} 962}
968EXPORT_SYMBOL(tcp_v4_md5_do_add); 963EXPORT_SYMBOL(tcp_md5_do_add);
969 964
970int tcp_v4_md5_do_del(struct sock *sk, __be32 addr) 965int tcp_md5_do_del(struct sock *sk, const union tcp_md5_addr *addr, int family)
971{ 966{
972 struct tcp_sock *tp = tcp_sk(sk); 967 struct tcp_sock *tp = tcp_sk(sk);
973 int i; 968 struct tcp_md5sig_key *key;
974 969
975 for (i = 0; i < tp->md5sig_info->entries4; i++) { 970 key = tcp_md5_do_lookup(sk, (union tcp_md5_addr *)&addr, AF_INET);
976 if (tp->md5sig_info->keys4[i].addr == addr) { 971 if (!key)
977 /* Free the key */ 972 return -ENOENT;
978 kfree(tp->md5sig_info->keys4[i].base.key); 973 hlist_del_rcu(&key->node);
979 tp->md5sig_info->entries4--; 974 kfree_rcu(key, rcu);
980 975 if (hlist_empty(&tp->md5sig_info->head))
981 if (tp->md5sig_info->entries4 == 0) { 976 tcp_free_md5sig_pool();
982 kfree(tp->md5sig_info->keys4); 977 return 0;
983 tp->md5sig_info->keys4 = NULL;
984 tp->md5sig_info->alloced4 = 0;
985 tcp_free_md5sig_pool();
986 } else if (tp->md5sig_info->entries4 != i) {
987 /* Need to do some manipulation */
988 memmove(&tp->md5sig_info->keys4[i],
989 &tp->md5sig_info->keys4[i+1],
990 (tp->md5sig_info->entries4 - i) *
991 sizeof(struct tcp4_md5sig_key));
992 }
993 return 0;
994 }
995 }
996 return -ENOENT;
997} 978}
998EXPORT_SYMBOL(tcp_v4_md5_do_del); 979EXPORT_SYMBOL(tcp_md5_do_del);
999 980
1000static void tcp_v4_clear_md5_list(struct sock *sk) 981void tcp_clear_md5_list(struct sock *sk)
1001{ 982{
1002 struct tcp_sock *tp = tcp_sk(sk); 983 struct tcp_sock *tp = tcp_sk(sk);
984 struct tcp_md5sig_key *key;
985 struct hlist_node *pos, *n;
1003 986
1004 /* Free each key, then the set of key keys, 987 if (!hlist_empty(&tp->md5sig_info->head))
1005 * the crypto element, and then decrement our
1006 * hold on the last resort crypto.
1007 */
1008 if (tp->md5sig_info->entries4) {
1009 int i;
1010 for (i = 0; i < tp->md5sig_info->entries4; i++)
1011 kfree(tp->md5sig_info->keys4[i].base.key);
1012 tp->md5sig_info->entries4 = 0;
1013 tcp_free_md5sig_pool(); 988 tcp_free_md5sig_pool();
1014 } 989 hlist_for_each_entry_safe(key, pos, n, &tp->md5sig_info->head, node) {
1015 if (tp->md5sig_info->keys4) { 990 hlist_del_rcu(&key->node);
1016 kfree(tp->md5sig_info->keys4); 991 kfree_rcu(key, rcu);
1017 tp->md5sig_info->keys4 = NULL;
1018 tp->md5sig_info->alloced4 = 0;
1019 } 992 }
1020} 993}
1021 994
@@ -1024,7 +997,6 @@ static int tcp_v4_parse_md5_keys(struct sock *sk, char __user *optval,
1024{ 997{
1025 struct tcp_md5sig cmd; 998 struct tcp_md5sig cmd;
1026 struct sockaddr_in *sin = (struct sockaddr_in *)&cmd.tcpm_addr; 999 struct sockaddr_in *sin = (struct sockaddr_in *)&cmd.tcpm_addr;
1027 u8 *newkey;
1028 1000
1029 if (optlen < sizeof(cmd)) 1001 if (optlen < sizeof(cmd))
1030 return -EINVAL; 1002 return -EINVAL;
@@ -1038,29 +1010,16 @@ static int tcp_v4_parse_md5_keys(struct sock *sk, char __user *optval,
1038 if (!cmd.tcpm_key || !cmd.tcpm_keylen) { 1010 if (!cmd.tcpm_key || !cmd.tcpm_keylen) {
1039 if (!tcp_sk(sk)->md5sig_info) 1011 if (!tcp_sk(sk)->md5sig_info)
1040 return -ENOENT; 1012 return -ENOENT;
1041 return tcp_v4_md5_do_del(sk, sin->sin_addr.s_addr); 1013 return tcp_md5_do_del(sk, (union tcp_md5_addr *)&sin->sin_addr.s_addr,
1014 AF_INET);
1042 } 1015 }
1043 1016
1044 if (cmd.tcpm_keylen > TCP_MD5SIG_MAXKEYLEN) 1017 if (cmd.tcpm_keylen > TCP_MD5SIG_MAXKEYLEN)
1045 return -EINVAL; 1018 return -EINVAL;
1046 1019
1047 if (!tcp_sk(sk)->md5sig_info) { 1020 return tcp_md5_do_add(sk, (union tcp_md5_addr *)&sin->sin_addr.s_addr,
1048 struct tcp_sock *tp = tcp_sk(sk); 1021 AF_INET, cmd.tcpm_key, cmd.tcpm_keylen,
1049 struct tcp_md5sig_info *p; 1022 GFP_KERNEL);
1050
1051 p = kzalloc(sizeof(*p), sk->sk_allocation);
1052 if (!p)
1053 return -EINVAL;
1054
1055 tp->md5sig_info = p;
1056 sk_nocaps_add(sk, NETIF_F_GSO_MASK);
1057 }
1058
1059 newkey = kmemdup(cmd.tcpm_key, cmd.tcpm_keylen, sk->sk_allocation);
1060 if (!newkey)
1061 return -ENOMEM;
1062 return tcp_v4_md5_do_add(sk, sin->sin_addr.s_addr,
1063 newkey, cmd.tcpm_keylen);
1064} 1023}
1065 1024
1066static int tcp_v4_md5_hash_pseudoheader(struct tcp_md5sig_pool *hp, 1025static int tcp_v4_md5_hash_pseudoheader(struct tcp_md5sig_pool *hp,
@@ -1086,7 +1045,7 @@ static int tcp_v4_md5_hash_pseudoheader(struct tcp_md5sig_pool *hp,
1086 return crypto_hash_update(&hp->md5_desc, &sg, sizeof(*bp)); 1045 return crypto_hash_update(&hp->md5_desc, &sg, sizeof(*bp));
1087} 1046}
1088 1047
1089static int tcp_v4_md5_hash_hdr(char *md5_hash, struct tcp_md5sig_key *key, 1048static int tcp_v4_md5_hash_hdr(char *md5_hash, const struct tcp_md5sig_key *key,
1090 __be32 daddr, __be32 saddr, const struct tcphdr *th) 1049 __be32 daddr, __be32 saddr, const struct tcphdr *th)
1091{ 1050{
1092 struct tcp_md5sig_pool *hp; 1051 struct tcp_md5sig_pool *hp;
@@ -1186,7 +1145,8 @@ static int tcp_v4_inbound_md5_hash(struct sock *sk, const struct sk_buff *skb)
1186 int genhash; 1145 int genhash;
1187 unsigned char newhash[16]; 1146 unsigned char newhash[16];
1188 1147
1189 hash_expected = tcp_v4_md5_do_lookup(sk, iph->saddr); 1148 hash_expected = tcp_md5_do_lookup(sk, (union tcp_md5_addr *)&iph->saddr,
1149 AF_INET);
1190 hash_location = tcp_parse_md5sig_option(th); 1150 hash_location = tcp_parse_md5sig_option(th);
1191 1151
1192 /* We've parsed the options - do we have a hash? */ 1152 /* We've parsed the options - do we have a hash? */
@@ -1474,7 +1434,8 @@ struct sock *tcp_v4_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
1474 1434
1475#ifdef CONFIG_TCP_MD5SIG 1435#ifdef CONFIG_TCP_MD5SIG
1476 /* Copy over the MD5 key from the original socket */ 1436 /* Copy over the MD5 key from the original socket */
1477 key = tcp_v4_md5_do_lookup(sk, newinet->inet_daddr); 1437 key = tcp_md5_do_lookup(sk, (union tcp_md5_addr *)&newinet->inet_daddr,
1438 AF_INET);
1478 if (key != NULL) { 1439 if (key != NULL) {
1479 /* 1440 /*
1480 * We're using one, so create a matching key 1441 * We're using one, so create a matching key
@@ -1482,10 +1443,8 @@ struct sock *tcp_v4_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
1482 * memory, then we end up not copying the key 1443 * memory, then we end up not copying the key
1483 * across. Shucks. 1444 * across. Shucks.
1484 */ 1445 */
1485 char *newkey = kmemdup(key->key, key->keylen, GFP_ATOMIC); 1446 tcp_md5_do_add(newsk, (union tcp_md5_addr *)&newinet->inet_daddr,
1486 if (newkey != NULL) 1447 AF_INET, key->key, key->keylen, GFP_ATOMIC);
1487 tcp_v4_md5_do_add(newsk, newinet->inet_daddr,
1488 newkey, key->keylen);
1489 sk_nocaps_add(newsk, NETIF_F_GSO_MASK); 1448 sk_nocaps_add(newsk, NETIF_F_GSO_MASK);
1490 } 1449 }
1491#endif 1450#endif
@@ -1934,7 +1893,7 @@ void tcp_v4_destroy_sock(struct sock *sk)
1934#ifdef CONFIG_TCP_MD5SIG 1893#ifdef CONFIG_TCP_MD5SIG
1935 /* Clean up the MD5 key list, if any */ 1894 /* Clean up the MD5 key list, if any */
1936 if (tp->md5sig_info) { 1895 if (tp->md5sig_info) {
1937 tcp_v4_clear_md5_list(sk); 1896 tcp_clear_md5_list(sk);
1938 kfree(tp->md5sig_info); 1897 kfree(tp->md5sig_info);
1939 tp->md5sig_info = NULL; 1898 tp->md5sig_info = NULL;
1940 } 1899 }
diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c
index 550e755747e0..3cabafb5cdd1 100644
--- a/net/ipv4/tcp_minisocks.c
+++ b/net/ipv4/tcp_minisocks.c
@@ -359,13 +359,11 @@ void tcp_time_wait(struct sock *sk, int state, int timeo)
359 */ 359 */
360 do { 360 do {
361 struct tcp_md5sig_key *key; 361 struct tcp_md5sig_key *key;
362 memset(tcptw->tw_md5_key, 0, sizeof(tcptw->tw_md5_key)); 362 tcptw->tw_md5_key = NULL;
363 tcptw->tw_md5_keylen = 0;
364 key = tp->af_specific->md5_lookup(sk, sk); 363 key = tp->af_specific->md5_lookup(sk, sk);
365 if (key != NULL) { 364 if (key != NULL) {
366 memcpy(&tcptw->tw_md5_key, key->key, key->keylen); 365 tcptw->tw_md5_key = kmemdup(key, sizeof(*key), GFP_ATOMIC);
367 tcptw->tw_md5_keylen = key->keylen; 366 if (tcptw->tw_md5_key && tcp_alloc_md5sig_pool(sk) == NULL)
368 if (tcp_alloc_md5sig_pool(sk) == NULL)
369 BUG(); 367 BUG();
370 } 368 }
371 } while (0); 369 } while (0);
@@ -405,8 +403,10 @@ void tcp_twsk_destructor(struct sock *sk)
405{ 403{
406#ifdef CONFIG_TCP_MD5SIG 404#ifdef CONFIG_TCP_MD5SIG
407 struct tcp_timewait_sock *twsk = tcp_twsk(sk); 405 struct tcp_timewait_sock *twsk = tcp_twsk(sk);
408 if (twsk->tw_md5_keylen) 406 if (twsk->tw_md5_key) {
409 tcp_free_md5sig_pool(); 407 tcp_free_md5sig_pool();
408 kfree_rcu(twsk->tw_md5_key, rcu);
409 }
410#endif 410#endif
411} 411}
412EXPORT_SYMBOL_GPL(tcp_twsk_destructor); 412EXPORT_SYMBOL_GPL(tcp_twsk_destructor);
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index f37769ea6375..bec41f9a6413 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -540,19 +540,7 @@ static void tcp_v6_reqsk_destructor(struct request_sock *req)
540static struct tcp_md5sig_key *tcp_v6_md5_do_lookup(struct sock *sk, 540static struct tcp_md5sig_key *tcp_v6_md5_do_lookup(struct sock *sk,
541 const struct in6_addr *addr) 541 const struct in6_addr *addr)
542{ 542{
543 struct tcp_sock *tp = tcp_sk(sk); 543 return tcp_md5_do_lookup(sk, (union tcp_md5_addr *)addr, AF_INET6);
544 int i;
545
546 BUG_ON(tp == NULL);
547
548 if (!tp->md5sig_info || !tp->md5sig_info->entries6)
549 return NULL;
550
551 for (i = 0; i < tp->md5sig_info->entries6; i++) {
552 if (ipv6_addr_equal(&tp->md5sig_info->keys6[i].addr, addr))
553 return &tp->md5sig_info->keys6[i].base;
554 }
555 return NULL;
556} 544}
557 545
558static struct tcp_md5sig_key *tcp_v6_md5_lookup(struct sock *sk, 546static struct tcp_md5sig_key *tcp_v6_md5_lookup(struct sock *sk,
@@ -567,129 +555,11 @@ static struct tcp_md5sig_key *tcp_v6_reqsk_md5_lookup(struct sock *sk,
567 return tcp_v6_md5_do_lookup(sk, &inet6_rsk(req)->rmt_addr); 555 return tcp_v6_md5_do_lookup(sk, &inet6_rsk(req)->rmt_addr);
568} 556}
569 557
570static int tcp_v6_md5_do_add(struct sock *sk, const struct in6_addr *peer,
571 char *newkey, u8 newkeylen)
572{
573 /* Add key to the list */
574 struct tcp_md5sig_key *key;
575 struct tcp_sock *tp = tcp_sk(sk);
576 struct tcp6_md5sig_key *keys;
577
578 key = tcp_v6_md5_do_lookup(sk, peer);
579 if (key) {
580 /* modify existing entry - just update that one */
581 kfree(key->key);
582 key->key = newkey;
583 key->keylen = newkeylen;
584 } else {
585 /* reallocate new list if current one is full. */
586 if (!tp->md5sig_info) {
587 tp->md5sig_info = kzalloc(sizeof(*tp->md5sig_info), GFP_ATOMIC);
588 if (!tp->md5sig_info) {
589 kfree(newkey);
590 return -ENOMEM;
591 }
592 sk_nocaps_add(sk, NETIF_F_GSO_MASK);
593 }
594 if (tp->md5sig_info->entries6 == 0 &&
595 tcp_alloc_md5sig_pool(sk) == NULL) {
596 kfree(newkey);
597 return -ENOMEM;
598 }
599 if (tp->md5sig_info->alloced6 == tp->md5sig_info->entries6) {
600 keys = kmalloc((sizeof (tp->md5sig_info->keys6[0]) *
601 (tp->md5sig_info->entries6 + 1)), GFP_ATOMIC);
602
603 if (!keys) {
604 kfree(newkey);
605 if (tp->md5sig_info->entries6 == 0)
606 tcp_free_md5sig_pool();
607 return -ENOMEM;
608 }
609
610 if (tp->md5sig_info->entries6)
611 memmove(keys, tp->md5sig_info->keys6,
612 (sizeof (tp->md5sig_info->keys6[0]) *
613 tp->md5sig_info->entries6));
614
615 kfree(tp->md5sig_info->keys6);
616 tp->md5sig_info->keys6 = keys;
617 tp->md5sig_info->alloced6++;
618 }
619
620 tp->md5sig_info->keys6[tp->md5sig_info->entries6].addr = *peer;
621 tp->md5sig_info->keys6[tp->md5sig_info->entries6].base.key = newkey;
622 tp->md5sig_info->keys6[tp->md5sig_info->entries6].base.keylen = newkeylen;
623
624 tp->md5sig_info->entries6++;
625 }
626 return 0;
627}
628
629static int tcp_v6_md5_do_del(struct sock *sk, const struct in6_addr *peer)
630{
631 struct tcp_sock *tp = tcp_sk(sk);
632 int i;
633
634 for (i = 0; i < tp->md5sig_info->entries6; i++) {
635 if (ipv6_addr_equal(&tp->md5sig_info->keys6[i].addr, peer)) {
636 /* Free the key */
637 kfree(tp->md5sig_info->keys6[i].base.key);
638 tp->md5sig_info->entries6--;
639
640 if (tp->md5sig_info->entries6 == 0) {
641 kfree(tp->md5sig_info->keys6);
642 tp->md5sig_info->keys6 = NULL;
643 tp->md5sig_info->alloced6 = 0;
644 tcp_free_md5sig_pool();
645 } else {
646 /* shrink the database */
647 if (tp->md5sig_info->entries6 != i)
648 memmove(&tp->md5sig_info->keys6[i],
649 &tp->md5sig_info->keys6[i+1],
650 (tp->md5sig_info->entries6 - i)
651 * sizeof (tp->md5sig_info->keys6[0]));
652 }
653 return 0;
654 }
655 }
656 return -ENOENT;
657}
658
659static void tcp_v6_clear_md5_list (struct sock *sk)
660{
661 struct tcp_sock *tp = tcp_sk(sk);
662 int i;
663
664 if (tp->md5sig_info->entries6) {
665 for (i = 0; i < tp->md5sig_info->entries6; i++)
666 kfree(tp->md5sig_info->keys6[i].base.key);
667 tp->md5sig_info->entries6 = 0;
668 tcp_free_md5sig_pool();
669 }
670
671 kfree(tp->md5sig_info->keys6);
672 tp->md5sig_info->keys6 = NULL;
673 tp->md5sig_info->alloced6 = 0;
674
675 if (tp->md5sig_info->entries4) {
676 for (i = 0; i < tp->md5sig_info->entries4; i++)
677 kfree(tp->md5sig_info->keys4[i].base.key);
678 tp->md5sig_info->entries4 = 0;
679 tcp_free_md5sig_pool();
680 }
681
682 kfree(tp->md5sig_info->keys4);
683 tp->md5sig_info->keys4 = NULL;
684 tp->md5sig_info->alloced4 = 0;
685}
686
687static int tcp_v6_parse_md5_keys (struct sock *sk, char __user *optval, 558static int tcp_v6_parse_md5_keys (struct sock *sk, char __user *optval,
688 int optlen) 559 int optlen)
689{ 560{
690 struct tcp_md5sig cmd; 561 struct tcp_md5sig cmd;
691 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&cmd.tcpm_addr; 562 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&cmd.tcpm_addr;
692 u8 *newkey;
693 563
694 if (optlen < sizeof(cmd)) 564 if (optlen < sizeof(cmd))
695 return -EINVAL; 565 return -EINVAL;
@@ -704,33 +574,21 @@ static int tcp_v6_parse_md5_keys (struct sock *sk, char __user *optval,
704 if (!tcp_sk(sk)->md5sig_info) 574 if (!tcp_sk(sk)->md5sig_info)
705 return -ENOENT; 575 return -ENOENT;
706 if (ipv6_addr_v4mapped(&sin6->sin6_addr)) 576 if (ipv6_addr_v4mapped(&sin6->sin6_addr))
707 return tcp_v4_md5_do_del(sk, sin6->sin6_addr.s6_addr32[3]); 577 return tcp_md5_do_del(sk, (union tcp_md5_addr *)&sin6->sin6_addr.s6_addr32[3],
708 return tcp_v6_md5_do_del(sk, &sin6->sin6_addr); 578 AF_INET);
579 return tcp_md5_do_del(sk, (union tcp_md5_addr *)&sin6->sin6_addr,
580 AF_INET6);
709 } 581 }
710 582
711 if (cmd.tcpm_keylen > TCP_MD5SIG_MAXKEYLEN) 583 if (cmd.tcpm_keylen > TCP_MD5SIG_MAXKEYLEN)
712 return -EINVAL; 584 return -EINVAL;
713 585
714 if (!tcp_sk(sk)->md5sig_info) { 586 if (ipv6_addr_v4mapped(&sin6->sin6_addr))
715 struct tcp_sock *tp = tcp_sk(sk); 587 return tcp_md5_do_add(sk, (union tcp_md5_addr *)&sin6->sin6_addr.s6_addr32[3],
716 struct tcp_md5sig_info *p; 588 AF_INET, cmd.tcpm_key, cmd.tcpm_keylen, GFP_KERNEL);
717
718 p = kzalloc(sizeof(struct tcp_md5sig_info), GFP_KERNEL);
719 if (!p)
720 return -ENOMEM;
721
722 tp->md5sig_info = p;
723 sk_nocaps_add(sk, NETIF_F_GSO_MASK);
724 }
725 589
726 newkey = kmemdup(cmd.tcpm_key, cmd.tcpm_keylen, GFP_KERNEL); 590 return tcp_md5_do_add(sk, (union tcp_md5_addr *)&sin6->sin6_addr,
727 if (!newkey) 591 AF_INET6, cmd.tcpm_key, cmd.tcpm_keylen, GFP_KERNEL);
728 return -ENOMEM;
729 if (ipv6_addr_v4mapped(&sin6->sin6_addr)) {
730 return tcp_v4_md5_do_add(sk, sin6->sin6_addr.s6_addr32[3],
731 newkey, cmd.tcpm_keylen);
732 }
733 return tcp_v6_md5_do_add(sk, &sin6->sin6_addr, newkey, cmd.tcpm_keylen);
734} 592}
735 593
736static int tcp_v6_md5_hash_pseudoheader(struct tcp_md5sig_pool *hp, 594static int tcp_v6_md5_hash_pseudoheader(struct tcp_md5sig_pool *hp,
@@ -1503,10 +1361,8 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
1503 * memory, then we end up not copying the key 1361 * memory, then we end up not copying the key
1504 * across. Shucks. 1362 * across. Shucks.
1505 */ 1363 */
1506 char *newkey = kmemdup(key->key, key->keylen, GFP_ATOMIC); 1364 tcp_md5_do_add(newsk, (union tcp_md5_addr *)&newnp->daddr,
1507 if (newkey != NULL) 1365 AF_INET6, key->key, key->keylen, GFP_ATOMIC);
1508 tcp_v6_md5_do_add(newsk, &newnp->daddr,
1509 newkey, key->keylen);
1510 } 1366 }
1511#endif 1367#endif
1512 1368
@@ -1995,11 +1851,6 @@ static int tcp_v6_init_sock(struct sock *sk)
1995 1851
1996static void tcp_v6_destroy_sock(struct sock *sk) 1852static void tcp_v6_destroy_sock(struct sock *sk)
1997{ 1853{
1998#ifdef CONFIG_TCP_MD5SIG
1999 /* Clean up the MD5 key list */
2000 if (tcp_sk(sk)->md5sig_info)
2001 tcp_v6_clear_md5_list(sk);
2002#endif
2003 tcp_v4_destroy_sock(sk); 1854 tcp_v4_destroy_sock(sk);
2004 inet6_destroy_sock(sk); 1855 inet6_destroy_sock(sk);
2005} 1856}