diff options
author | David S. Miller <davem@davemloft.net> | 2008-06-12 01:33:59 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-06-12 01:33:59 -0400 |
commit | e6e30add6bd8115af108de2a13ec82d997a55777 (patch) | |
tree | 558b4d1c3ac369805aa9c57abca710bdf52aff75 /net/ipv6/tcp_ipv6.c | |
parent | d4c3c0753594adaafbcb77a086f013f1d847b3f0 (diff) | |
parent | 9501f9722922f2e80e1f9dc6682311d65c2b5690 (diff) |
Merge branch 'net-next-2.6-misc-20080612a' of git://git.linux-ipv6.org/gitroot/yoshfuji/linux-2.6-next
Diffstat (limited to 'net/ipv6/tcp_ipv6.c')
-rw-r--r-- | net/ipv6/tcp_ipv6.c | 136 |
1 files changed, 25 insertions, 111 deletions
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 155499197fc5..3fe736bead96 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c | |||
@@ -80,6 +80,12 @@ static struct inet_connection_sock_af_ops ipv6_specific; | |||
80 | #ifdef CONFIG_TCP_MD5SIG | 80 | #ifdef CONFIG_TCP_MD5SIG |
81 | static struct tcp_sock_af_ops tcp_sock_ipv6_specific; | 81 | static struct tcp_sock_af_ops tcp_sock_ipv6_specific; |
82 | static struct tcp_sock_af_ops tcp_sock_ipv6_mapped_specific; | 82 | static struct tcp_sock_af_ops tcp_sock_ipv6_mapped_specific; |
83 | #else | ||
84 | static struct tcp_md5sig_key *tcp_v6_md5_do_lookup(struct sock *sk, | ||
85 | struct in6_addr *addr) | ||
86 | { | ||
87 | return NULL; | ||
88 | } | ||
83 | #endif | 89 | #endif |
84 | 90 | ||
85 | static void tcp_v6_hash(struct sock *sk) | 91 | static void tcp_v6_hash(struct sock *sk) |
@@ -734,78 +740,34 @@ static int tcp_v6_parse_md5_keys (struct sock *sk, char __user *optval, | |||
734 | static int tcp_v6_do_calc_md5_hash(char *md5_hash, struct tcp_md5sig_key *key, | 740 | static int tcp_v6_do_calc_md5_hash(char *md5_hash, struct tcp_md5sig_key *key, |
735 | struct in6_addr *saddr, | 741 | struct in6_addr *saddr, |
736 | struct in6_addr *daddr, | 742 | struct in6_addr *daddr, |
737 | struct tcphdr *th, int protocol, | 743 | struct tcphdr *th, unsigned int tcplen) |
738 | unsigned int tcplen) | ||
739 | { | 744 | { |
740 | struct scatterlist sg[4]; | ||
741 | __u16 data_len; | ||
742 | int block = 0; | ||
743 | __sum16 cksum; | ||
744 | struct tcp_md5sig_pool *hp; | 745 | struct tcp_md5sig_pool *hp; |
745 | struct tcp6_pseudohdr *bp; | 746 | struct tcp6_pseudohdr *bp; |
746 | struct hash_desc *desc; | ||
747 | int err; | 747 | int err; |
748 | unsigned int nbytes = 0; | ||
749 | 748 | ||
750 | hp = tcp_get_md5sig_pool(); | 749 | hp = tcp_get_md5sig_pool(); |
751 | if (!hp) { | 750 | if (!hp) { |
752 | printk(KERN_WARNING "%s(): hash pool not found...\n", __func__); | 751 | printk(KERN_WARNING "%s(): hash pool not found...\n", __func__); |
753 | goto clear_hash_noput; | 752 | goto clear_hash_noput; |
754 | } | 753 | } |
754 | |||
755 | bp = &hp->md5_blk.ip6; | 755 | bp = &hp->md5_blk.ip6; |
756 | desc = &hp->md5_desc; | ||
757 | 756 | ||
758 | /* 1. TCP pseudo-header (RFC2460) */ | 757 | /* 1. TCP pseudo-header (RFC2460) */ |
759 | ipv6_addr_copy(&bp->saddr, saddr); | 758 | ipv6_addr_copy(&bp->saddr, saddr); |
760 | ipv6_addr_copy(&bp->daddr, daddr); | 759 | ipv6_addr_copy(&bp->daddr, daddr); |
761 | bp->len = htonl(tcplen); | 760 | bp->len = htonl(tcplen); |
762 | bp->protocol = htonl(protocol); | 761 | bp->protocol = htonl(IPPROTO_TCP); |
763 | |||
764 | sg_init_table(sg, 4); | ||
765 | 762 | ||
766 | sg_set_buf(&sg[block++], bp, sizeof(*bp)); | 763 | err = tcp_calc_md5_hash(md5_hash, key, sizeof(*bp), |
767 | nbytes += sizeof(*bp); | 764 | th, tcplen, hp); |
768 | 765 | ||
769 | /* 2. TCP header, excluding options */ | 766 | if (err) |
770 | cksum = th->check; | ||
771 | th->check = 0; | ||
772 | sg_set_buf(&sg[block++], th, sizeof(*th)); | ||
773 | nbytes += sizeof(*th); | ||
774 | |||
775 | /* 3. TCP segment data (if any) */ | ||
776 | data_len = tcplen - (th->doff << 2); | ||
777 | if (data_len > 0) { | ||
778 | u8 *data = (u8 *)th + (th->doff << 2); | ||
779 | sg_set_buf(&sg[block++], data, data_len); | ||
780 | nbytes += data_len; | ||
781 | } | ||
782 | |||
783 | /* 4. shared key */ | ||
784 | sg_set_buf(&sg[block++], key->key, key->keylen); | ||
785 | nbytes += key->keylen; | ||
786 | |||
787 | sg_mark_end(&sg[block - 1]); | ||
788 | |||
789 | /* Now store the hash into the packet */ | ||
790 | err = crypto_hash_init(desc); | ||
791 | if (err) { | ||
792 | printk(KERN_WARNING "%s(): hash_init failed\n", __func__); | ||
793 | goto clear_hash; | ||
794 | } | ||
795 | err = crypto_hash_update(desc, sg, nbytes); | ||
796 | if (err) { | ||
797 | printk(KERN_WARNING "%s(): hash_update failed\n", __func__); | ||
798 | goto clear_hash; | ||
799 | } | ||
800 | err = crypto_hash_final(desc, md5_hash); | ||
801 | if (err) { | ||
802 | printk(KERN_WARNING "%s(): hash_final failed\n", __func__); | ||
803 | goto clear_hash; | 767 | goto clear_hash; |
804 | } | ||
805 | 768 | ||
806 | /* Reset header, and free up the crypto */ | 769 | /* Free up the crypto pool */ |
807 | tcp_put_md5sig_pool(); | 770 | tcp_put_md5sig_pool(); |
808 | th->check = cksum; | ||
809 | out: | 771 | out: |
810 | return 0; | 772 | return 0; |
811 | clear_hash: | 773 | clear_hash: |
@@ -819,8 +781,7 @@ static int tcp_v6_calc_md5_hash(char *md5_hash, struct tcp_md5sig_key *key, | |||
819 | struct sock *sk, | 781 | struct sock *sk, |
820 | struct dst_entry *dst, | 782 | struct dst_entry *dst, |
821 | struct request_sock *req, | 783 | struct request_sock *req, |
822 | struct tcphdr *th, int protocol, | 784 | struct tcphdr *th, unsigned int tcplen) |
823 | unsigned int tcplen) | ||
824 | { | 785 | { |
825 | struct in6_addr *saddr, *daddr; | 786 | struct in6_addr *saddr, *daddr; |
826 | 787 | ||
@@ -833,7 +794,7 @@ static int tcp_v6_calc_md5_hash(char *md5_hash, struct tcp_md5sig_key *key, | |||
833 | } | 794 | } |
834 | return tcp_v6_do_calc_md5_hash(md5_hash, key, | 795 | return tcp_v6_do_calc_md5_hash(md5_hash, key, |
835 | saddr, daddr, | 796 | saddr, daddr, |
836 | th, protocol, tcplen); | 797 | th, tcplen); |
837 | } | 798 | } |
838 | 799 | ||
839 | static int tcp_v6_inbound_md5_hash (struct sock *sk, struct sk_buff *skb) | 800 | static int tcp_v6_inbound_md5_hash (struct sock *sk, struct sk_buff *skb) |
@@ -842,43 +803,12 @@ static int tcp_v6_inbound_md5_hash (struct sock *sk, struct sk_buff *skb) | |||
842 | struct tcp_md5sig_key *hash_expected; | 803 | struct tcp_md5sig_key *hash_expected; |
843 | struct ipv6hdr *ip6h = ipv6_hdr(skb); | 804 | struct ipv6hdr *ip6h = ipv6_hdr(skb); |
844 | struct tcphdr *th = tcp_hdr(skb); | 805 | struct tcphdr *th = tcp_hdr(skb); |
845 | int length = (th->doff << 2) - sizeof (*th); | ||
846 | int genhash; | 806 | int genhash; |
847 | u8 *ptr; | ||
848 | u8 newhash[16]; | 807 | u8 newhash[16]; |
849 | 808 | ||
850 | hash_expected = tcp_v6_md5_do_lookup(sk, &ip6h->saddr); | 809 | hash_expected = tcp_v6_md5_do_lookup(sk, &ip6h->saddr); |
810 | hash_location = tcp_parse_md5sig_option(th); | ||
851 | 811 | ||
852 | /* If the TCP option is too short, we can short cut */ | ||
853 | if (length < TCPOLEN_MD5SIG) | ||
854 | return hash_expected ? 1 : 0; | ||
855 | |||
856 | /* parse options */ | ||
857 | ptr = (u8*)(th + 1); | ||
858 | while (length > 0) { | ||
859 | int opcode = *ptr++; | ||
860 | int opsize; | ||
861 | |||
862 | switch(opcode) { | ||
863 | case TCPOPT_EOL: | ||
864 | goto done_opts; | ||
865 | case TCPOPT_NOP: | ||
866 | length--; | ||
867 | continue; | ||
868 | default: | ||
869 | opsize = *ptr++; | ||
870 | if (opsize < 2 || opsize > length) | ||
871 | goto done_opts; | ||
872 | if (opcode == TCPOPT_MD5SIG) { | ||
873 | hash_location = ptr; | ||
874 | goto done_opts; | ||
875 | } | ||
876 | } | ||
877 | ptr += opsize - 2; | ||
878 | length -= opsize; | ||
879 | } | ||
880 | |||
881 | done_opts: | ||
882 | /* do we have a hash as expected? */ | 812 | /* do we have a hash as expected? */ |
883 | if (!hash_expected) { | 813 | if (!hash_expected) { |
884 | if (!hash_location) | 814 | if (!hash_location) |
@@ -908,8 +838,7 @@ done_opts: | |||
908 | genhash = tcp_v6_do_calc_md5_hash(newhash, | 838 | genhash = tcp_v6_do_calc_md5_hash(newhash, |
909 | hash_expected, | 839 | hash_expected, |
910 | &ip6h->saddr, &ip6h->daddr, | 840 | &ip6h->saddr, &ip6h->daddr, |
911 | th, sk->sk_protocol, | 841 | th, skb->len); |
912 | skb->len); | ||
913 | if (genhash || memcmp(hash_location, newhash, 16) != 0) { | 842 | if (genhash || memcmp(hash_location, newhash, 16) != 0) { |
914 | if (net_ratelimit()) { | 843 | if (net_ratelimit()) { |
915 | printk(KERN_INFO "MD5 Hash %s for " | 844 | printk(KERN_INFO "MD5 Hash %s for " |
@@ -1049,7 +978,7 @@ static void tcp_v6_send_reset(struct sock *sk, struct sk_buff *skb) | |||
1049 | tcp_v6_do_calc_md5_hash((__u8 *)&opt[1], key, | 978 | tcp_v6_do_calc_md5_hash((__u8 *)&opt[1], key, |
1050 | &ipv6_hdr(skb)->daddr, | 979 | &ipv6_hdr(skb)->daddr, |
1051 | &ipv6_hdr(skb)->saddr, | 980 | &ipv6_hdr(skb)->saddr, |
1052 | t1, IPPROTO_TCP, tot_len); | 981 | t1, tot_len); |
1053 | } | 982 | } |
1054 | #endif | 983 | #endif |
1055 | 984 | ||
@@ -1086,8 +1015,8 @@ static void tcp_v6_send_reset(struct sock *sk, struct sk_buff *skb) | |||
1086 | kfree_skb(buff); | 1015 | kfree_skb(buff); |
1087 | } | 1016 | } |
1088 | 1017 | ||
1089 | static void tcp_v6_send_ack(struct tcp_timewait_sock *tw, | 1018 | static void tcp_v6_send_ack(struct sk_buff *skb, u32 seq, u32 ack, u32 win, u32 ts, |
1090 | struct sk_buff *skb, u32 seq, u32 ack, u32 win, u32 ts) | 1019 | struct tcp_md5sig_key *key) |
1091 | { | 1020 | { |
1092 | struct tcphdr *th = tcp_hdr(skb), *t1; | 1021 | struct tcphdr *th = tcp_hdr(skb), *t1; |
1093 | struct sk_buff *buff; | 1022 | struct sk_buff *buff; |
@@ -1096,22 +1025,6 @@ static void tcp_v6_send_ack(struct tcp_timewait_sock *tw, | |||
1096 | struct sock *ctl_sk = net->ipv6.tcp_sk; | 1025 | struct sock *ctl_sk = net->ipv6.tcp_sk; |
1097 | unsigned int tot_len = sizeof(struct tcphdr); | 1026 | unsigned int tot_len = sizeof(struct tcphdr); |
1098 | __be32 *topt; | 1027 | __be32 *topt; |
1099 | #ifdef CONFIG_TCP_MD5SIG | ||
1100 | struct tcp_md5sig_key *key; | ||
1101 | struct tcp_md5sig_key tw_key; | ||
1102 | #endif | ||
1103 | |||
1104 | #ifdef CONFIG_TCP_MD5SIG | ||
1105 | if (!tw && skb->sk) { | ||
1106 | key = tcp_v6_md5_do_lookup(skb->sk, &ipv6_hdr(skb)->daddr); | ||
1107 | } else if (tw && tw->tw_md5_keylen) { | ||
1108 | tw_key.key = tw->tw_md5_key; | ||
1109 | tw_key.keylen = tw->tw_md5_keylen; | ||
1110 | key = &tw_key; | ||
1111 | } else { | ||
1112 | key = NULL; | ||
1113 | } | ||
1114 | #endif | ||
1115 | 1028 | ||
1116 | if (ts) | 1029 | if (ts) |
1117 | tot_len += TCPOLEN_TSTAMP_ALIGNED; | 1030 | tot_len += TCPOLEN_TSTAMP_ALIGNED; |
@@ -1155,7 +1068,7 @@ static void tcp_v6_send_ack(struct tcp_timewait_sock *tw, | |||
1155 | tcp_v6_do_calc_md5_hash((__u8 *)topt, key, | 1068 | tcp_v6_do_calc_md5_hash((__u8 *)topt, key, |
1156 | &ipv6_hdr(skb)->daddr, | 1069 | &ipv6_hdr(skb)->daddr, |
1157 | &ipv6_hdr(skb)->saddr, | 1070 | &ipv6_hdr(skb)->saddr, |
1158 | t1, IPPROTO_TCP, tot_len); | 1071 | t1, tot_len); |
1159 | } | 1072 | } |
1160 | #endif | 1073 | #endif |
1161 | 1074 | ||
@@ -1191,16 +1104,17 @@ static void tcp_v6_timewait_ack(struct sock *sk, struct sk_buff *skb) | |||
1191 | struct inet_timewait_sock *tw = inet_twsk(sk); | 1104 | struct inet_timewait_sock *tw = inet_twsk(sk); |
1192 | struct tcp_timewait_sock *tcptw = tcp_twsk(sk); | 1105 | struct tcp_timewait_sock *tcptw = tcp_twsk(sk); |
1193 | 1106 | ||
1194 | tcp_v6_send_ack(tcptw, skb, tcptw->tw_snd_nxt, tcptw->tw_rcv_nxt, | 1107 | tcp_v6_send_ack(skb, tcptw->tw_snd_nxt, tcptw->tw_rcv_nxt, |
1195 | tcptw->tw_rcv_wnd >> tw->tw_rcv_wscale, | 1108 | tcptw->tw_rcv_wnd >> tw->tw_rcv_wscale, |
1196 | tcptw->tw_ts_recent); | 1109 | tcptw->tw_ts_recent, tcp_twsk_md5_key(tcptw)); |
1197 | 1110 | ||
1198 | inet_twsk_put(tw); | 1111 | inet_twsk_put(tw); |
1199 | } | 1112 | } |
1200 | 1113 | ||
1201 | static void tcp_v6_reqsk_send_ack(struct sk_buff *skb, struct request_sock *req) | 1114 | static void tcp_v6_reqsk_send_ack(struct sk_buff *skb, struct request_sock *req) |
1202 | { | 1115 | { |
1203 | tcp_v6_send_ack(NULL, skb, tcp_rsk(req)->snt_isn + 1, tcp_rsk(req)->rcv_isn + 1, req->rcv_wnd, req->ts_recent); | 1116 | tcp_v6_send_ack(skb, tcp_rsk(req)->snt_isn + 1, tcp_rsk(req)->rcv_isn + 1, req->rcv_wnd, req->ts_recent, |
1117 | tcp_v6_md5_do_lookup(skb->sk, &ipv6_hdr(skb)->daddr)); | ||
1204 | } | 1118 | } |
1205 | 1119 | ||
1206 | 1120 | ||