aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4/tcp_ipv4.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv4/tcp_ipv4.c')
-rw-r--r--net/ipv4/tcp_ipv4.c140
1 files changed, 85 insertions, 55 deletions
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index 29adc668ad51..5400d75ff17a 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -87,9 +87,8 @@ int sysctl_tcp_low_latency __read_mostly;
87#ifdef CONFIG_TCP_MD5SIG 87#ifdef CONFIG_TCP_MD5SIG
88static struct tcp_md5sig_key *tcp_v4_md5_do_lookup(struct sock *sk, 88static struct tcp_md5sig_key *tcp_v4_md5_do_lookup(struct sock *sk,
89 __be32 addr); 89 __be32 addr);
90static int tcp_v4_do_calc_md5_hash(char *md5_hash, struct tcp_md5sig_key *key, 90static int tcp_v4_md5_hash_hdr(char *md5_hash, struct tcp_md5sig_key *key,
91 __be32 saddr, __be32 daddr, 91 __be32 daddr, __be32 saddr, struct tcphdr *th);
92 struct tcphdr *th, unsigned int tcplen);
93#else 92#else
94static inline 93static inline
95struct tcp_md5sig_key *tcp_v4_md5_do_lookup(struct sock *sk, __be32 addr) 94struct tcp_md5sig_key *tcp_v4_md5_do_lookup(struct sock *sk, __be32 addr)
@@ -583,11 +582,9 @@ static void tcp_v4_send_reset(struct sock *sk, struct sk_buff *skb)
583 arg.iov[0].iov_len += TCPOLEN_MD5SIG_ALIGNED; 582 arg.iov[0].iov_len += TCPOLEN_MD5SIG_ALIGNED;
584 rep.th.doff = arg.iov[0].iov_len / 4; 583 rep.th.doff = arg.iov[0].iov_len / 4;
585 584
586 tcp_v4_do_calc_md5_hash((__u8 *)&rep.opt[1], 585 tcp_v4_md5_hash_hdr((__u8 *) &rep.opt[1],
587 key, 586 key, ip_hdr(skb)->daddr,
588 ip_hdr(skb)->daddr, 587 ip_hdr(skb)->saddr, &rep.th);
589 ip_hdr(skb)->saddr,
590 &rep.th, arg.iov[0].iov_len);
591 } 588 }
592#endif 589#endif
593 arg.csum = csum_tcpudp_nofold(ip_hdr(skb)->daddr, 590 arg.csum = csum_tcpudp_nofold(ip_hdr(skb)->daddr,
@@ -657,11 +654,9 @@ static void tcp_v4_send_ack(struct sk_buff *skb, u32 seq, u32 ack,
657 arg.iov[0].iov_len += TCPOLEN_MD5SIG_ALIGNED; 654 arg.iov[0].iov_len += TCPOLEN_MD5SIG_ALIGNED;
658 rep.th.doff = arg.iov[0].iov_len/4; 655 rep.th.doff = arg.iov[0].iov_len/4;
659 656
660 tcp_v4_do_calc_md5_hash((__u8 *)&rep.opt[offset], 657 tcp_v4_md5_hash_hdr((__u8 *) &rep.opt[offset],
661 key, 658 key, ip_hdr(skb)->daddr,
662 ip_hdr(skb)->daddr, 659 ip_hdr(skb)->saddr, &rep.th);
663 ip_hdr(skb)->saddr,
664 &rep.th, arg.iov[0].iov_len);
665 } 660 }
666#endif 661#endif
667 arg.csum = csum_tcpudp_nofold(ip_hdr(skb)->daddr, 662 arg.csum = csum_tcpudp_nofold(ip_hdr(skb)->daddr,
@@ -989,28 +984,16 @@ static int tcp_v4_parse_md5_keys(struct sock *sk, char __user *optval,
989 newkey, cmd.tcpm_keylen); 984 newkey, cmd.tcpm_keylen);
990} 985}
991 986
992static int tcp_v4_do_calc_md5_hash(char *md5_hash, struct tcp_md5sig_key *key, 987static int tcp_v4_md5_hash_pseudoheader(struct tcp_md5sig_pool *hp,
993 __be32 saddr, __be32 daddr, 988 __be32 daddr, __be32 saddr, int nbytes)
994 struct tcphdr *th,
995 unsigned int tcplen)
996{ 989{
997 struct tcp_md5sig_pool *hp;
998 struct tcp4_pseudohdr *bp; 990 struct tcp4_pseudohdr *bp;
999 int err; 991 struct scatterlist sg;
1000
1001 /*
1002 * Okay, so RFC2385 is turned on for this connection,
1003 * so we need to generate the MD5 hash for the packet now.
1004 */
1005
1006 hp = tcp_get_md5sig_pool();
1007 if (!hp)
1008 goto clear_hash_noput;
1009 992
1010 bp = &hp->md5_blk.ip4; 993 bp = &hp->md5_blk.ip4;
1011 994
1012 /* 995 /*
1013 * The TCP pseudo-header (in the order: source IP address, 996 * 1. the TCP pseudo-header (in the order: source IP address,
1014 * destination IP address, zero-padded protocol number, and 997 * destination IP address, zero-padded protocol number, and
1015 * segment length) 998 * segment length)
1016 */ 999 */
@@ -1018,48 +1001,95 @@ static int tcp_v4_do_calc_md5_hash(char *md5_hash, struct tcp_md5sig_key *key,
1018 bp->daddr = daddr; 1001 bp->daddr = daddr;
1019 bp->pad = 0; 1002 bp->pad = 0;
1020 bp->protocol = IPPROTO_TCP; 1003 bp->protocol = IPPROTO_TCP;
1021 bp->len = htons(tcplen); 1004 bp->len = cpu_to_be16(nbytes);
1022 1005
1023 err = tcp_calc_md5_hash(md5_hash, key, sizeof(*bp), 1006 sg_init_one(&sg, bp, sizeof(*bp));
1024 th, tcplen, hp); 1007 return crypto_hash_update(&hp->md5_desc, &sg, sizeof(*bp));
1025 if (err) 1008}
1009
1010static int tcp_v4_md5_hash_hdr(char *md5_hash, struct tcp_md5sig_key *key,
1011 __be32 daddr, __be32 saddr, struct tcphdr *th)
1012{
1013 struct tcp_md5sig_pool *hp;
1014 struct hash_desc *desc;
1015
1016 hp = tcp_get_md5sig_pool();
1017 if (!hp)
1018 goto clear_hash_noput;
1019 desc = &hp->md5_desc;
1020
1021 if (crypto_hash_init(desc))
1022 goto clear_hash;
1023 if (tcp_v4_md5_hash_pseudoheader(hp, daddr, saddr, th->doff << 2))
1024 goto clear_hash;
1025 if (tcp_md5_hash_header(hp, th))
1026 goto clear_hash;
1027 if (tcp_md5_hash_key(hp, key))
1028 goto clear_hash;
1029 if (crypto_hash_final(desc, md5_hash))
1026 goto clear_hash; 1030 goto clear_hash;
1027 1031
1028 /* Free up the crypto pool */
1029 tcp_put_md5sig_pool(); 1032 tcp_put_md5sig_pool();
1030out:
1031 return 0; 1033 return 0;
1034
1032clear_hash: 1035clear_hash:
1033 tcp_put_md5sig_pool(); 1036 tcp_put_md5sig_pool();
1034clear_hash_noput: 1037clear_hash_noput:
1035 memset(md5_hash, 0, 16); 1038 memset(md5_hash, 0, 16);
1036 goto out; 1039 return 1;
1037} 1040}
1038 1041
1039int tcp_v4_calc_md5_hash(char *md5_hash, struct tcp_md5sig_key *key, 1042int tcp_v4_md5_hash_skb(char *md5_hash, struct tcp_md5sig_key *key,
1040 struct sock *sk, 1043 struct sock *sk, struct request_sock *req,
1041 struct dst_entry *dst, 1044 struct sk_buff *skb)
1042 struct request_sock *req,
1043 struct tcphdr *th,
1044 unsigned int tcplen)
1045{ 1045{
1046 struct tcp_md5sig_pool *hp;
1047 struct hash_desc *desc;
1048 struct tcphdr *th = tcp_hdr(skb);
1046 __be32 saddr, daddr; 1049 __be32 saddr, daddr;
1047 1050
1048 if (sk) { 1051 if (sk) {
1049 saddr = inet_sk(sk)->saddr; 1052 saddr = inet_sk(sk)->saddr;
1050 daddr = inet_sk(sk)->daddr; 1053 daddr = inet_sk(sk)->daddr;
1054 } else if (req) {
1055 saddr = inet_rsk(req)->loc_addr;
1056 daddr = inet_rsk(req)->rmt_addr;
1051 } else { 1057 } else {
1052 struct rtable *rt = (struct rtable *)dst; 1058 const struct iphdr *iph = ip_hdr(skb);
1053 BUG_ON(!rt); 1059 saddr = iph->saddr;
1054 saddr = rt->rt_src; 1060 daddr = iph->daddr;
1055 daddr = rt->rt_dst;
1056 } 1061 }
1057 return tcp_v4_do_calc_md5_hash(md5_hash, key, 1062
1058 saddr, daddr, 1063 hp = tcp_get_md5sig_pool();
1059 th, tcplen); 1064 if (!hp)
1065 goto clear_hash_noput;
1066 desc = &hp->md5_desc;
1067
1068 if (crypto_hash_init(desc))
1069 goto clear_hash;
1070
1071 if (tcp_v4_md5_hash_pseudoheader(hp, daddr, saddr, skb->len))
1072 goto clear_hash;
1073 if (tcp_md5_hash_header(hp, th))
1074 goto clear_hash;
1075 if (tcp_md5_hash_skb_data(hp, skb, th->doff << 2))
1076 goto clear_hash;
1077 if (tcp_md5_hash_key(hp, key))
1078 goto clear_hash;
1079 if (crypto_hash_final(desc, md5_hash))
1080 goto clear_hash;
1081
1082 tcp_put_md5sig_pool();
1083 return 0;
1084
1085clear_hash:
1086 tcp_put_md5sig_pool();
1087clear_hash_noput:
1088 memset(md5_hash, 0, 16);
1089 return 1;
1060} 1090}
1061 1091
1062EXPORT_SYMBOL(tcp_v4_calc_md5_hash); 1092EXPORT_SYMBOL(tcp_v4_md5_hash_skb);
1063 1093
1064static int tcp_v4_inbound_md5_hash(struct sock *sk, struct sk_buff *skb) 1094static int tcp_v4_inbound_md5_hash(struct sock *sk, struct sk_buff *skb)
1065{ 1095{
@@ -1104,10 +1134,9 @@ static int tcp_v4_inbound_md5_hash(struct sock *sk, struct sk_buff *skb)
1104 /* Okay, so this is hash_expected and hash_location - 1134 /* Okay, so this is hash_expected and hash_location -
1105 * so we need to calculate the checksum. 1135 * so we need to calculate the checksum.
1106 */ 1136 */
1107 genhash = tcp_v4_do_calc_md5_hash(newhash, 1137 genhash = tcp_v4_md5_hash_skb(newhash,
1108 hash_expected, 1138 hash_expected,
1109 iph->saddr, iph->daddr, 1139 NULL, NULL, skb);
1110 th, skb->len);
1111 1140
1112 if (genhash || memcmp(hash_location, newhash, 16) != 0) { 1141 if (genhash || memcmp(hash_location, newhash, 16) != 0) {
1113 if (net_ratelimit()) { 1142 if (net_ratelimit()) {
@@ -1356,6 +1385,7 @@ struct sock *tcp_v4_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
1356 if (newkey != NULL) 1385 if (newkey != NULL)
1357 tcp_v4_md5_do_add(newsk, inet_sk(sk)->daddr, 1386 tcp_v4_md5_do_add(newsk, inet_sk(sk)->daddr,
1358 newkey, key->keylen); 1387 newkey, key->keylen);
1388 newsk->sk_route_caps &= ~NETIF_F_GSO_MASK;
1359 } 1389 }
1360#endif 1390#endif
1361 1391
@@ -1719,7 +1749,7 @@ struct inet_connection_sock_af_ops ipv4_specific = {
1719#ifdef CONFIG_TCP_MD5SIG 1749#ifdef CONFIG_TCP_MD5SIG
1720static struct tcp_sock_af_ops tcp_sock_ipv4_specific = { 1750static struct tcp_sock_af_ops tcp_sock_ipv4_specific = {
1721 .md5_lookup = tcp_v4_md5_lookup, 1751 .md5_lookup = tcp_v4_md5_lookup,
1722 .calc_md5_hash = tcp_v4_calc_md5_hash, 1752 .calc_md5_hash = tcp_v4_md5_hash_skb,
1723 .md5_add = tcp_v4_md5_add_func, 1753 .md5_add = tcp_v4_md5_add_func,
1724 .md5_parse = tcp_v4_parse_md5_keys, 1754 .md5_parse = tcp_v4_parse_md5_keys,
1725}; 1755};