aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv6')
-rw-r--r--net/ipv6/tcp_ipv6.c127
1 files changed, 83 insertions, 44 deletions
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index ca5b93a5c02a..ae45f9835014 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -736,64 +736,105 @@ static int tcp_v6_parse_md5_keys (struct sock *sk, char __user *optval,
736 return tcp_v6_md5_do_add(sk, &sin6->sin6_addr, newkey, cmd.tcpm_keylen); 736 return tcp_v6_md5_do_add(sk, &sin6->sin6_addr, newkey, cmd.tcpm_keylen);
737} 737}
738 738
739static int tcp_v6_do_calc_md5_hash(char *md5_hash, struct tcp_md5sig_key *key, 739static int tcp_v6_md5_hash_pseudoheader(struct tcp_md5sig_pool *hp,
740 struct in6_addr *saddr, 740 struct in6_addr *daddr,
741 struct in6_addr *daddr, 741 struct in6_addr *saddr, int nbytes)
742 struct tcphdr *th, unsigned int tcplen)
743{ 742{
744 struct tcp_md5sig_pool *hp;
745 struct tcp6_pseudohdr *bp; 743 struct tcp6_pseudohdr *bp;
746 int err; 744 struct scatterlist sg;
747
748 hp = tcp_get_md5sig_pool();
749 if (!hp) {
750 printk(KERN_WARNING "%s(): hash pool not found...\n", __func__);
751 goto clear_hash_noput;
752 }
753 745
754 bp = &hp->md5_blk.ip6; 746 bp = &hp->md5_blk.ip6;
755
756 /* 1. TCP pseudo-header (RFC2460) */ 747 /* 1. TCP pseudo-header (RFC2460) */
757 ipv6_addr_copy(&bp->saddr, saddr); 748 ipv6_addr_copy(&bp->saddr, saddr);
758 ipv6_addr_copy(&bp->daddr, daddr); 749 ipv6_addr_copy(&bp->daddr, daddr);
759 bp->len = htonl(tcplen); 750 bp->protocol = cpu_to_be32(IPPROTO_TCP);
760 bp->protocol = htonl(IPPROTO_TCP); 751 bp->len = cpu_to_be16(nbytes);
761 752
762 err = tcp_calc_md5_hash(md5_hash, key, sizeof(*bp), 753 sg_init_one(&sg, bp, sizeof(*bp));
763 th, tcplen, hp); 754 return crypto_hash_update(&hp->md5_desc, &sg, sizeof(*bp));
755}
764 756
765 if (err) 757static int tcp_v6_md5_hash_hdr(char *md5_hash, struct tcp_md5sig_key *key,
758 struct in6_addr *daddr, struct in6_addr *saddr,
759 struct tcphdr *th)
760{
761 struct tcp_md5sig_pool *hp;
762 struct hash_desc *desc;
763
764 hp = tcp_get_md5sig_pool();
765 if (!hp)
766 goto clear_hash_noput;
767 desc = &hp->md5_desc;
768
769 if (crypto_hash_init(desc))
770 goto clear_hash;
771 if (tcp_v6_md5_hash_pseudoheader(hp, daddr, saddr, th->doff << 2))
772 goto clear_hash;
773 if (tcp_md5_hash_header(hp, th))
774 goto clear_hash;
775 if (tcp_md5_hash_key(hp, key))
776 goto clear_hash;
777 if (crypto_hash_final(desc, md5_hash))
766 goto clear_hash; 778 goto clear_hash;
767 779
768 /* Free up the crypto pool */
769 tcp_put_md5sig_pool(); 780 tcp_put_md5sig_pool();
770out:
771 return 0; 781 return 0;
782
772clear_hash: 783clear_hash:
773 tcp_put_md5sig_pool(); 784 tcp_put_md5sig_pool();
774clear_hash_noput: 785clear_hash_noput:
775 memset(md5_hash, 0, 16); 786 memset(md5_hash, 0, 16);
776 goto out; 787 return 1;
777} 788}
778 789
779static int tcp_v6_calc_md5_hash(char *md5_hash, struct tcp_md5sig_key *key, 790static int tcp_v6_md5_hash_skb(char *md5_hash, struct tcp_md5sig_key *key,
780 struct sock *sk, 791 struct sock *sk, struct request_sock *req,
781 struct dst_entry *dst, 792 struct sk_buff *skb)
782 struct request_sock *req,
783 struct tcphdr *th, unsigned int tcplen)
784{ 793{
785 struct in6_addr *saddr, *daddr; 794 struct in6_addr *saddr, *daddr;
795 struct tcp_md5sig_pool *hp;
796 struct hash_desc *desc;
797 struct tcphdr *th = tcp_hdr(skb);
786 798
787 if (sk) { 799 if (sk) {
788 saddr = &inet6_sk(sk)->saddr; 800 saddr = &inet6_sk(sk)->saddr;
789 daddr = &inet6_sk(sk)->daddr; 801 daddr = &inet6_sk(sk)->daddr;
790 } else { 802 } else if (req) {
791 saddr = &inet6_rsk(req)->loc_addr; 803 saddr = &inet6_rsk(req)->loc_addr;
792 daddr = &inet6_rsk(req)->rmt_addr; 804 daddr = &inet6_rsk(req)->rmt_addr;
805 } else {
806 struct ipv6hdr *ip6h = ipv6_hdr(skb);
807 saddr = &ip6h->saddr;
808 daddr = &ip6h->daddr;
793 } 809 }
794 return tcp_v6_do_calc_md5_hash(md5_hash, key, 810
795 saddr, daddr, 811 hp = tcp_get_md5sig_pool();
796 th, tcplen); 812 if (!hp)
813 goto clear_hash_noput;
814 desc = &hp->md5_desc;
815
816 if (crypto_hash_init(desc))
817 goto clear_hash;
818
819 if (tcp_v6_md5_hash_pseudoheader(hp, daddr, saddr, skb->len))
820 goto clear_hash;
821 if (tcp_md5_hash_header(hp, th))
822 goto clear_hash;
823 if (tcp_md5_hash_skb_data(hp, skb, th->doff << 2))
824 goto clear_hash;
825 if (tcp_md5_hash_key(hp, key))
826 goto clear_hash;
827 if (crypto_hash_final(desc, md5_hash))
828 goto clear_hash;
829
830 tcp_put_md5sig_pool();
831 return 0;
832
833clear_hash:
834 tcp_put_md5sig_pool();
835clear_hash_noput:
836 memset(md5_hash, 0, 16);
837 return 1;
797} 838}
798 839
799static int tcp_v6_inbound_md5_hash (struct sock *sk, struct sk_buff *skb) 840static int tcp_v6_inbound_md5_hash (struct sock *sk, struct sk_buff *skb)
@@ -834,10 +875,10 @@ static int tcp_v6_inbound_md5_hash (struct sock *sk, struct sk_buff *skb)
834 } 875 }
835 876
836 /* check the signature */ 877 /* check the signature */
837 genhash = tcp_v6_do_calc_md5_hash(newhash, 878 genhash = tcp_v6_md5_hash_skb(newhash,
838 hash_expected, 879 hash_expected,
839 &ip6h->saddr, &ip6h->daddr, 880 NULL, NULL, skb);
840 th, skb->len); 881
841 if (genhash || memcmp(hash_location, newhash, 16) != 0) { 882 if (genhash || memcmp(hash_location, newhash, 16) != 0) {
842 if (net_ratelimit()) { 883 if (net_ratelimit()) {
843 printk(KERN_INFO "MD5 Hash %s for " 884 printk(KERN_INFO "MD5 Hash %s for "
@@ -974,10 +1015,9 @@ static void tcp_v6_send_reset(struct sock *sk, struct sk_buff *skb)
974 (TCPOPT_NOP << 16) | 1015 (TCPOPT_NOP << 16) |
975 (TCPOPT_MD5SIG << 8) | 1016 (TCPOPT_MD5SIG << 8) |
976 TCPOLEN_MD5SIG); 1017 TCPOLEN_MD5SIG);
977 tcp_v6_do_calc_md5_hash((__u8 *)&opt[1], key, 1018 tcp_v6_md5_hash_hdr((__u8 *)&opt[1], key,
978 &ipv6_hdr(skb)->daddr, 1019 &ipv6_hdr(skb)->daddr,
979 &ipv6_hdr(skb)->saddr, 1020 &ipv6_hdr(skb)->saddr, t1);
980 t1, tot_len);
981 } 1021 }
982#endif 1022#endif
983 1023
@@ -1064,10 +1104,9 @@ static void tcp_v6_send_ack(struct sk_buff *skb, u32 seq, u32 ack, u32 win, u32
1064 if (key) { 1104 if (key) {
1065 *topt++ = htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) | 1105 *topt++ = htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) |
1066 (TCPOPT_MD5SIG << 8) | TCPOLEN_MD5SIG); 1106 (TCPOPT_MD5SIG << 8) | TCPOLEN_MD5SIG);
1067 tcp_v6_do_calc_md5_hash((__u8 *)topt, key, 1107 tcp_v6_md5_hash_hdr((__u8 *)topt, key,
1068 &ipv6_hdr(skb)->daddr, 1108 &ipv6_hdr(skb)->daddr,
1069 &ipv6_hdr(skb)->saddr, 1109 &ipv6_hdr(skb)->saddr, t1);
1070 t1, tot_len);
1071 } 1110 }
1072#endif 1111#endif
1073 1112
@@ -1783,7 +1822,7 @@ static struct inet_connection_sock_af_ops ipv6_specific = {
1783#ifdef CONFIG_TCP_MD5SIG 1822#ifdef CONFIG_TCP_MD5SIG
1784static struct tcp_sock_af_ops tcp_sock_ipv6_specific = { 1823static struct tcp_sock_af_ops tcp_sock_ipv6_specific = {
1785 .md5_lookup = tcp_v6_md5_lookup, 1824 .md5_lookup = tcp_v6_md5_lookup,
1786 .calc_md5_hash = tcp_v6_calc_md5_hash, 1825 .calc_md5_hash = tcp_v6_md5_hash_skb,
1787 .md5_add = tcp_v6_md5_add_func, 1826 .md5_add = tcp_v6_md5_add_func,
1788 .md5_parse = tcp_v6_parse_md5_keys, 1827 .md5_parse = tcp_v6_parse_md5_keys,
1789}; 1828};
@@ -1815,7 +1854,7 @@ static struct inet_connection_sock_af_ops ipv6_mapped = {
1815#ifdef CONFIG_TCP_MD5SIG 1854#ifdef CONFIG_TCP_MD5SIG
1816static struct tcp_sock_af_ops tcp_sock_ipv6_mapped_specific = { 1855static struct tcp_sock_af_ops tcp_sock_ipv6_mapped_specific = {
1817 .md5_lookup = tcp_v4_md5_lookup, 1856 .md5_lookup = tcp_v4_md5_lookup,
1818 .calc_md5_hash = tcp_v4_calc_md5_hash, 1857 .calc_md5_hash = tcp_v4_md5_hash_skb,
1819 .md5_add = tcp_v6_md5_add_func, 1858 .md5_add = tcp_v6_md5_add_func,
1820 .md5_parse = tcp_v6_parse_md5_keys, 1859 .md5_parse = tcp_v6_parse_md5_keys,
1821}; 1860};