aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6/tcp_ipv6.c
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2008-06-12 01:33:59 -0400
committerDavid S. Miller <davem@davemloft.net>2008-06-12 01:33:59 -0400
commite6e30add6bd8115af108de2a13ec82d997a55777 (patch)
tree558b4d1c3ac369805aa9c57abca710bdf52aff75 /net/ipv6/tcp_ipv6.c
parentd4c3c0753594adaafbcb77a086f013f1d847b3f0 (diff)
parent9501f9722922f2e80e1f9dc6682311d65c2b5690 (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.c136
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
81static struct tcp_sock_af_ops tcp_sock_ipv6_specific; 81static struct tcp_sock_af_ops tcp_sock_ipv6_specific;
82static struct tcp_sock_af_ops tcp_sock_ipv6_mapped_specific; 82static struct tcp_sock_af_ops tcp_sock_ipv6_mapped_specific;
83#else
84static 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
85static void tcp_v6_hash(struct sock *sk) 91static void tcp_v6_hash(struct sock *sk)
@@ -734,78 +740,34 @@ static int tcp_v6_parse_md5_keys (struct sock *sk, char __user *optval,
734static int tcp_v6_do_calc_md5_hash(char *md5_hash, struct tcp_md5sig_key *key, 740static 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;
809out: 771out:
810 return 0; 772 return 0;
811clear_hash: 773clear_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
839static int tcp_v6_inbound_md5_hash (struct sock *sk, struct sk_buff *skb) 800static 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
881done_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
1089static void tcp_v6_send_ack(struct tcp_timewait_sock *tw, 1018static 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
1201static void tcp_v6_reqsk_send_ack(struct sk_buff *skb, struct request_sock *req) 1114static 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