diff options
Diffstat (limited to 'net/ipv6/tcp_ipv6.c')
-rw-r--r-- | net/ipv6/tcp_ipv6.c | 144 |
1 files changed, 27 insertions, 117 deletions
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 40ea9c36d24..30dbab7cc3c 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c | |||
@@ -5,8 +5,6 @@ | |||
5 | * Authors: | 5 | * Authors: |
6 | * Pedro Roque <roque@di.fc.ul.pt> | 6 | * Pedro Roque <roque@di.fc.ul.pt> |
7 | * | 7 | * |
8 | * $Id: tcp_ipv6.c,v 1.144 2002/02/01 22:01:04 davem Exp $ | ||
9 | * | ||
10 | * Based on: | 8 | * Based on: |
11 | * linux/net/ipv4/tcp.c | 9 | * linux/net/ipv4/tcp.c |
12 | * linux/net/ipv4/tcp_input.c | 10 | * linux/net/ipv4/tcp_input.c |
@@ -72,8 +70,6 @@ | |||
72 | 70 | ||
73 | static void tcp_v6_send_reset(struct sock *sk, struct sk_buff *skb); | 71 | static void tcp_v6_send_reset(struct sock *sk, struct sk_buff *skb); |
74 | static void tcp_v6_reqsk_send_ack(struct sk_buff *skb, struct request_sock *req); | 72 | static void tcp_v6_reqsk_send_ack(struct sk_buff *skb, struct request_sock *req); |
75 | static void tcp_v6_send_check(struct sock *sk, int len, | ||
76 | struct sk_buff *skb); | ||
77 | 73 | ||
78 | static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb); | 74 | static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb); |
79 | 75 | ||
@@ -82,6 +78,12 @@ static struct inet_connection_sock_af_ops ipv6_specific; | |||
82 | #ifdef CONFIG_TCP_MD5SIG | 78 | #ifdef CONFIG_TCP_MD5SIG |
83 | static struct tcp_sock_af_ops tcp_sock_ipv6_specific; | 79 | static struct tcp_sock_af_ops tcp_sock_ipv6_specific; |
84 | static struct tcp_sock_af_ops tcp_sock_ipv6_mapped_specific; | 80 | static struct tcp_sock_af_ops tcp_sock_ipv6_mapped_specific; |
81 | #else | ||
82 | static struct tcp_md5sig_key *tcp_v6_md5_do_lookup(struct sock *sk, | ||
83 | struct in6_addr *addr) | ||
84 | { | ||
85 | return NULL; | ||
86 | } | ||
85 | #endif | 87 | #endif |
86 | 88 | ||
87 | static void tcp_v6_hash(struct sock *sk) | 89 | static void tcp_v6_hash(struct sock *sk) |
@@ -736,78 +738,34 @@ static int tcp_v6_parse_md5_keys (struct sock *sk, char __user *optval, | |||
736 | static int tcp_v6_do_calc_md5_hash(char *md5_hash, struct tcp_md5sig_key *key, | 738 | static int tcp_v6_do_calc_md5_hash(char *md5_hash, struct tcp_md5sig_key *key, |
737 | struct in6_addr *saddr, | 739 | struct in6_addr *saddr, |
738 | struct in6_addr *daddr, | 740 | struct in6_addr *daddr, |
739 | struct tcphdr *th, int protocol, | 741 | struct tcphdr *th, unsigned int tcplen) |
740 | unsigned int tcplen) | ||
741 | { | 742 | { |
742 | struct scatterlist sg[4]; | ||
743 | __u16 data_len; | ||
744 | int block = 0; | ||
745 | __sum16 cksum; | ||
746 | struct tcp_md5sig_pool *hp; | 743 | struct tcp_md5sig_pool *hp; |
747 | struct tcp6_pseudohdr *bp; | 744 | struct tcp6_pseudohdr *bp; |
748 | struct hash_desc *desc; | ||
749 | int err; | 745 | int err; |
750 | unsigned int nbytes = 0; | ||
751 | 746 | ||
752 | hp = tcp_get_md5sig_pool(); | 747 | hp = tcp_get_md5sig_pool(); |
753 | if (!hp) { | 748 | if (!hp) { |
754 | printk(KERN_WARNING "%s(): hash pool not found...\n", __func__); | 749 | printk(KERN_WARNING "%s(): hash pool not found...\n", __func__); |
755 | goto clear_hash_noput; | 750 | goto clear_hash_noput; |
756 | } | 751 | } |
752 | |||
757 | bp = &hp->md5_blk.ip6; | 753 | bp = &hp->md5_blk.ip6; |
758 | desc = &hp->md5_desc; | ||
759 | 754 | ||
760 | /* 1. TCP pseudo-header (RFC2460) */ | 755 | /* 1. TCP pseudo-header (RFC2460) */ |
761 | ipv6_addr_copy(&bp->saddr, saddr); | 756 | ipv6_addr_copy(&bp->saddr, saddr); |
762 | ipv6_addr_copy(&bp->daddr, daddr); | 757 | ipv6_addr_copy(&bp->daddr, daddr); |
763 | bp->len = htonl(tcplen); | 758 | bp->len = htonl(tcplen); |
764 | bp->protocol = htonl(protocol); | 759 | bp->protocol = htonl(IPPROTO_TCP); |
765 | |||
766 | sg_init_table(sg, 4); | ||
767 | 760 | ||
768 | sg_set_buf(&sg[block++], bp, sizeof(*bp)); | 761 | err = tcp_calc_md5_hash(md5_hash, key, sizeof(*bp), |
769 | nbytes += sizeof(*bp); | 762 | th, tcplen, hp); |
770 | 763 | ||
771 | /* 2. TCP header, excluding options */ | 764 | if (err) |
772 | cksum = th->check; | ||
773 | th->check = 0; | ||
774 | sg_set_buf(&sg[block++], th, sizeof(*th)); | ||
775 | nbytes += sizeof(*th); | ||
776 | |||
777 | /* 3. TCP segment data (if any) */ | ||
778 | data_len = tcplen - (th->doff << 2); | ||
779 | if (data_len > 0) { | ||
780 | u8 *data = (u8 *)th + (th->doff << 2); | ||
781 | sg_set_buf(&sg[block++], data, data_len); | ||
782 | nbytes += data_len; | ||
783 | } | ||
784 | |||
785 | /* 4. shared key */ | ||
786 | sg_set_buf(&sg[block++], key->key, key->keylen); | ||
787 | nbytes += key->keylen; | ||
788 | |||
789 | sg_mark_end(&sg[block - 1]); | ||
790 | |||
791 | /* Now store the hash into the packet */ | ||
792 | err = crypto_hash_init(desc); | ||
793 | if (err) { | ||
794 | printk(KERN_WARNING "%s(): hash_init failed\n", __func__); | ||
795 | goto clear_hash; | ||
796 | } | ||
797 | err = crypto_hash_update(desc, sg, nbytes); | ||
798 | if (err) { | ||
799 | printk(KERN_WARNING "%s(): hash_update failed\n", __func__); | ||
800 | goto clear_hash; | ||
801 | } | ||
802 | err = crypto_hash_final(desc, md5_hash); | ||
803 | if (err) { | ||
804 | printk(KERN_WARNING "%s(): hash_final failed\n", __func__); | ||
805 | goto clear_hash; | 765 | goto clear_hash; |
806 | } | ||
807 | 766 | ||
808 | /* Reset header, and free up the crypto */ | 767 | /* Free up the crypto pool */ |
809 | tcp_put_md5sig_pool(); | 768 | tcp_put_md5sig_pool(); |
810 | th->check = cksum; | ||
811 | out: | 769 | out: |
812 | return 0; | 770 | return 0; |
813 | clear_hash: | 771 | clear_hash: |
@@ -821,8 +779,7 @@ static int tcp_v6_calc_md5_hash(char *md5_hash, struct tcp_md5sig_key *key, | |||
821 | struct sock *sk, | 779 | struct sock *sk, |
822 | struct dst_entry *dst, | 780 | struct dst_entry *dst, |
823 | struct request_sock *req, | 781 | struct request_sock *req, |
824 | struct tcphdr *th, int protocol, | 782 | struct tcphdr *th, unsigned int tcplen) |
825 | unsigned int tcplen) | ||
826 | { | 783 | { |
827 | struct in6_addr *saddr, *daddr; | 784 | struct in6_addr *saddr, *daddr; |
828 | 785 | ||
@@ -835,7 +792,7 @@ static int tcp_v6_calc_md5_hash(char *md5_hash, struct tcp_md5sig_key *key, | |||
835 | } | 792 | } |
836 | return tcp_v6_do_calc_md5_hash(md5_hash, key, | 793 | return tcp_v6_do_calc_md5_hash(md5_hash, key, |
837 | saddr, daddr, | 794 | saddr, daddr, |
838 | th, protocol, tcplen); | 795 | th, tcplen); |
839 | } | 796 | } |
840 | 797 | ||
841 | static int tcp_v6_inbound_md5_hash (struct sock *sk, struct sk_buff *skb) | 798 | static int tcp_v6_inbound_md5_hash (struct sock *sk, struct sk_buff *skb) |
@@ -844,43 +801,12 @@ static int tcp_v6_inbound_md5_hash (struct sock *sk, struct sk_buff *skb) | |||
844 | struct tcp_md5sig_key *hash_expected; | 801 | struct tcp_md5sig_key *hash_expected; |
845 | struct ipv6hdr *ip6h = ipv6_hdr(skb); | 802 | struct ipv6hdr *ip6h = ipv6_hdr(skb); |
846 | struct tcphdr *th = tcp_hdr(skb); | 803 | struct tcphdr *th = tcp_hdr(skb); |
847 | int length = (th->doff << 2) - sizeof (*th); | ||
848 | int genhash; | 804 | int genhash; |
849 | u8 *ptr; | ||
850 | u8 newhash[16]; | 805 | u8 newhash[16]; |
851 | 806 | ||
852 | hash_expected = tcp_v6_md5_do_lookup(sk, &ip6h->saddr); | 807 | hash_expected = tcp_v6_md5_do_lookup(sk, &ip6h->saddr); |
808 | hash_location = tcp_parse_md5sig_option(th); | ||
853 | 809 | ||
854 | /* If the TCP option is too short, we can short cut */ | ||
855 | if (length < TCPOLEN_MD5SIG) | ||
856 | return hash_expected ? 1 : 0; | ||
857 | |||
858 | /* parse options */ | ||
859 | ptr = (u8*)(th + 1); | ||
860 | while (length > 0) { | ||
861 | int opcode = *ptr++; | ||
862 | int opsize; | ||
863 | |||
864 | switch(opcode) { | ||
865 | case TCPOPT_EOL: | ||
866 | goto done_opts; | ||
867 | case TCPOPT_NOP: | ||
868 | length--; | ||
869 | continue; | ||
870 | default: | ||
871 | opsize = *ptr++; | ||
872 | if (opsize < 2 || opsize > length) | ||
873 | goto done_opts; | ||
874 | if (opcode == TCPOPT_MD5SIG) { | ||
875 | hash_location = ptr; | ||
876 | goto done_opts; | ||
877 | } | ||
878 | } | ||
879 | ptr += opsize - 2; | ||
880 | length -= opsize; | ||
881 | } | ||
882 | |||
883 | done_opts: | ||
884 | /* do we have a hash as expected? */ | 810 | /* do we have a hash as expected? */ |
885 | if (!hash_expected) { | 811 | if (!hash_expected) { |
886 | if (!hash_location) | 812 | if (!hash_location) |
@@ -910,8 +836,7 @@ done_opts: | |||
910 | genhash = tcp_v6_do_calc_md5_hash(newhash, | 836 | genhash = tcp_v6_do_calc_md5_hash(newhash, |
911 | hash_expected, | 837 | hash_expected, |
912 | &ip6h->saddr, &ip6h->daddr, | 838 | &ip6h->saddr, &ip6h->daddr, |
913 | th, sk->sk_protocol, | 839 | th, skb->len); |
914 | skb->len); | ||
915 | if (genhash || memcmp(hash_location, newhash, 16) != 0) { | 840 | if (genhash || memcmp(hash_location, newhash, 16) != 0) { |
916 | if (net_ratelimit()) { | 841 | if (net_ratelimit()) { |
917 | printk(KERN_INFO "MD5 Hash %s for " | 842 | printk(KERN_INFO "MD5 Hash %s for " |
@@ -1051,7 +976,7 @@ static void tcp_v6_send_reset(struct sock *sk, struct sk_buff *skb) | |||
1051 | tcp_v6_do_calc_md5_hash((__u8 *)&opt[1], key, | 976 | tcp_v6_do_calc_md5_hash((__u8 *)&opt[1], key, |
1052 | &ipv6_hdr(skb)->daddr, | 977 | &ipv6_hdr(skb)->daddr, |
1053 | &ipv6_hdr(skb)->saddr, | 978 | &ipv6_hdr(skb)->saddr, |
1054 | t1, IPPROTO_TCP, tot_len); | 979 | t1, tot_len); |
1055 | } | 980 | } |
1056 | #endif | 981 | #endif |
1057 | 982 | ||
@@ -1088,8 +1013,8 @@ static void tcp_v6_send_reset(struct sock *sk, struct sk_buff *skb) | |||
1088 | kfree_skb(buff); | 1013 | kfree_skb(buff); |
1089 | } | 1014 | } |
1090 | 1015 | ||
1091 | static void tcp_v6_send_ack(struct tcp_timewait_sock *tw, | 1016 | static void tcp_v6_send_ack(struct sk_buff *skb, u32 seq, u32 ack, u32 win, u32 ts, |
1092 | struct sk_buff *skb, u32 seq, u32 ack, u32 win, u32 ts) | 1017 | struct tcp_md5sig_key *key) |
1093 | { | 1018 | { |
1094 | struct tcphdr *th = tcp_hdr(skb), *t1; | 1019 | struct tcphdr *th = tcp_hdr(skb), *t1; |
1095 | struct sk_buff *buff; | 1020 | struct sk_buff *buff; |
@@ -1098,22 +1023,6 @@ static void tcp_v6_send_ack(struct tcp_timewait_sock *tw, | |||
1098 | struct sock *ctl_sk = net->ipv6.tcp_sk; | 1023 | struct sock *ctl_sk = net->ipv6.tcp_sk; |
1099 | unsigned int tot_len = sizeof(struct tcphdr); | 1024 | unsigned int tot_len = sizeof(struct tcphdr); |
1100 | __be32 *topt; | 1025 | __be32 *topt; |
1101 | #ifdef CONFIG_TCP_MD5SIG | ||
1102 | struct tcp_md5sig_key *key; | ||
1103 | struct tcp_md5sig_key tw_key; | ||
1104 | #endif | ||
1105 | |||
1106 | #ifdef CONFIG_TCP_MD5SIG | ||
1107 | if (!tw && skb->sk) { | ||
1108 | key = tcp_v6_md5_do_lookup(skb->sk, &ipv6_hdr(skb)->daddr); | ||
1109 | } else if (tw && tw->tw_md5_keylen) { | ||
1110 | tw_key.key = tw->tw_md5_key; | ||
1111 | tw_key.keylen = tw->tw_md5_keylen; | ||
1112 | key = &tw_key; | ||
1113 | } else { | ||
1114 | key = NULL; | ||
1115 | } | ||
1116 | #endif | ||
1117 | 1026 | ||
1118 | if (ts) | 1027 | if (ts) |
1119 | tot_len += TCPOLEN_TSTAMP_ALIGNED; | 1028 | tot_len += TCPOLEN_TSTAMP_ALIGNED; |
@@ -1157,7 +1066,7 @@ static void tcp_v6_send_ack(struct tcp_timewait_sock *tw, | |||
1157 | tcp_v6_do_calc_md5_hash((__u8 *)topt, key, | 1066 | tcp_v6_do_calc_md5_hash((__u8 *)topt, key, |
1158 | &ipv6_hdr(skb)->daddr, | 1067 | &ipv6_hdr(skb)->daddr, |
1159 | &ipv6_hdr(skb)->saddr, | 1068 | &ipv6_hdr(skb)->saddr, |
1160 | t1, IPPROTO_TCP, tot_len); | 1069 | t1, tot_len); |
1161 | } | 1070 | } |
1162 | #endif | 1071 | #endif |
1163 | 1072 | ||
@@ -1193,16 +1102,17 @@ static void tcp_v6_timewait_ack(struct sock *sk, struct sk_buff *skb) | |||
1193 | struct inet_timewait_sock *tw = inet_twsk(sk); | 1102 | struct inet_timewait_sock *tw = inet_twsk(sk); |
1194 | struct tcp_timewait_sock *tcptw = tcp_twsk(sk); | 1103 | struct tcp_timewait_sock *tcptw = tcp_twsk(sk); |
1195 | 1104 | ||
1196 | tcp_v6_send_ack(tcptw, skb, tcptw->tw_snd_nxt, tcptw->tw_rcv_nxt, | 1105 | tcp_v6_send_ack(skb, tcptw->tw_snd_nxt, tcptw->tw_rcv_nxt, |
1197 | tcptw->tw_rcv_wnd >> tw->tw_rcv_wscale, | 1106 | tcptw->tw_rcv_wnd >> tw->tw_rcv_wscale, |
1198 | tcptw->tw_ts_recent); | 1107 | tcptw->tw_ts_recent, tcp_twsk_md5_key(tcptw)); |
1199 | 1108 | ||
1200 | inet_twsk_put(tw); | 1109 | inet_twsk_put(tw); |
1201 | } | 1110 | } |
1202 | 1111 | ||
1203 | static void tcp_v6_reqsk_send_ack(struct sk_buff *skb, struct request_sock *req) | 1112 | static void tcp_v6_reqsk_send_ack(struct sk_buff *skb, struct request_sock *req) |
1204 | { | 1113 | { |
1205 | tcp_v6_send_ack(NULL, skb, tcp_rsk(req)->snt_isn + 1, tcp_rsk(req)->rcv_isn + 1, req->rcv_wnd, req->ts_recent); | 1114 | tcp_v6_send_ack(skb, tcp_rsk(req)->snt_isn + 1, tcp_rsk(req)->rcv_isn + 1, req->rcv_wnd, req->ts_recent, |
1115 | tcp_v6_md5_do_lookup(skb->sk, &ipv6_hdr(skb)->daddr)); | ||
1206 | } | 1116 | } |
1207 | 1117 | ||
1208 | 1118 | ||
@@ -1960,7 +1870,7 @@ static int tcp_v6_init_sock(struct sock *sk) | |||
1960 | return 0; | 1870 | return 0; |
1961 | } | 1871 | } |
1962 | 1872 | ||
1963 | static int tcp_v6_destroy_sock(struct sock *sk) | 1873 | static void tcp_v6_destroy_sock(struct sock *sk) |
1964 | { | 1874 | { |
1965 | #ifdef CONFIG_TCP_MD5SIG | 1875 | #ifdef CONFIG_TCP_MD5SIG |
1966 | /* Clean up the MD5 key list */ | 1876 | /* Clean up the MD5 key list */ |
@@ -1968,7 +1878,7 @@ static int tcp_v6_destroy_sock(struct sock *sk) | |||
1968 | tcp_v6_clear_md5_list(sk); | 1878 | tcp_v6_clear_md5_list(sk); |
1969 | #endif | 1879 | #endif |
1970 | tcp_v4_destroy_sock(sk); | 1880 | tcp_v4_destroy_sock(sk); |
1971 | return inet6_destroy_sock(sk); | 1881 | inet6_destroy_sock(sk); |
1972 | } | 1882 | } |
1973 | 1883 | ||
1974 | #ifdef CONFIG_PROC_FS | 1884 | #ifdef CONFIG_PROC_FS |