aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>2008-04-17 00:19:16 -0400
committerYOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>2008-06-11 13:38:20 -0400
commit8d26d76dd4a4c87ef037a44a42a0608ffc730199 (patch)
tree884ff53a83e460aa3f1837cc336a5a34f364156e
parent076fb7223357769c39f3ddf900bba6752369c76a (diff)
tcp md5sig: Share most of hash calcucaltion bits between IPv4 and IPv6.
We can share most part of the hash calculation code because the only difference between IPv4 and IPv6 is their pseudo headers. Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
-rw-r--r--include/net/tcp.h7
-rw-r--r--net/ipv4/tcp.c70
-rw-r--r--net/ipv4/tcp_ipv4.c52
-rw-r--r--net/ipv6/tcp_ipv6.c53
4 files changed, 86 insertions, 96 deletions
diff --git a/include/net/tcp.h b/include/net/tcp.h
index ae2549c45fc7..eac26b73bcc3 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -1117,6 +1117,13 @@ struct tcp_md5sig_pool {
1117#define TCP_MD5SIG_MAXKEYS (~(u32)0) /* really?! */ 1117#define TCP_MD5SIG_MAXKEYS (~(u32)0) /* really?! */
1118 1118
1119/* - functions */ 1119/* - functions */
1120extern int tcp_calc_md5_hash(char *md5_hash,
1121 struct tcp_md5sig_key *key,
1122 int bplen,
1123 struct tcphdr *th,
1124 unsigned int tcplen,
1125 struct tcp_md5sig_pool *hp);
1126
1120extern int tcp_v4_calc_md5_hash(char *md5_hash, 1127extern int tcp_v4_calc_md5_hash(char *md5_hash,
1121 struct tcp_md5sig_key *key, 1128 struct tcp_md5sig_key *key,
1122 struct sock *sk, 1129 struct sock *sk,
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index ab66683b8043..6efbae0e5512 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -2459,6 +2459,76 @@ static unsigned long tcp_md5sig_users;
2459static struct tcp_md5sig_pool **tcp_md5sig_pool; 2459static struct tcp_md5sig_pool **tcp_md5sig_pool;
2460static DEFINE_SPINLOCK(tcp_md5sig_pool_lock); 2460static DEFINE_SPINLOCK(tcp_md5sig_pool_lock);
2461 2461
2462int tcp_calc_md5_hash(char *md5_hash, struct tcp_md5sig_key *key,
2463 int bplen,
2464 struct tcphdr *th, unsigned int tcplen,
2465 struct tcp_md5sig_pool *hp)
2466{
2467 struct scatterlist sg[4];
2468 __u16 data_len;
2469 int block = 0;
2470 __sum16 cksum;
2471 struct hash_desc *desc = &hp->md5_desc;
2472 int err;
2473 unsigned int nbytes = 0;
2474
2475 sg_init_table(sg, 4);
2476
2477 /* 1. The TCP pseudo-header */
2478 sg_set_buf(&sg[block++], &hp->md5_blk, bplen);
2479 nbytes += bplen;
2480
2481 /* 2. The TCP header, excluding options, and assuming a
2482 * checksum of zero
2483 */
2484 cksum = th->check;
2485 th->check = 0;
2486 sg_set_buf(&sg[block++], th, sizeof(*th));
2487 nbytes += sizeof(*th);
2488
2489 /* 3. The TCP segment data (if any) */
2490 data_len = tcplen - (th->doff << 2);
2491 if (data_len > 0) {
2492 u8 *data = (u8 *)th + (th->doff << 2);
2493 sg_set_buf(&sg[block++], data, data_len);
2494 nbytes += data_len;
2495 }
2496
2497 /* 4. an independently-specified key or password, known to both
2498 * TCPs and presumably connection-specific
2499 */
2500 sg_set_buf(&sg[block++], key->key, key->keylen);
2501 nbytes += key->keylen;
2502
2503 sg_mark_end(&sg[block - 1]);
2504
2505 /* Now store the hash into the packet */
2506 err = crypto_hash_init(desc);
2507 if (err) {
2508 if (net_ratelimit())
2509 printk(KERN_WARNING "%s(): hash_init failed\n", __func__);
2510 return -1;
2511 }
2512 err = crypto_hash_update(desc, sg, nbytes);
2513 if (err) {
2514 if (net_ratelimit())
2515 printk(KERN_WARNING "%s(): hash_update failed\n", __func__);
2516 return -1;
2517 }
2518 err = crypto_hash_final(desc, md5_hash);
2519 if (err) {
2520 if (net_ratelimit())
2521 printk(KERN_WARNING "%s(): hash_final failed\n", __func__);
2522 return -1;
2523 }
2524
2525 /* Reset header */
2526 th->check = cksum;
2527
2528 return 0;
2529}
2530EXPORT_SYMBOL(tcp_calc_md5_hash);
2531
2462static void __tcp_free_md5sig_pool(struct tcp_md5sig_pool **pool) 2532static void __tcp_free_md5sig_pool(struct tcp_md5sig_pool **pool)
2463{ 2533{
2464 int cpu; 2534 int cpu;
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index f25445d21bdf..e331cdbd0953 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -1006,15 +1006,9 @@ static int tcp_v4_do_calc_md5_hash(char *md5_hash, struct tcp_md5sig_key *key,
1006 struct tcphdr *th, 1006 struct tcphdr *th,
1007 unsigned int tcplen) 1007 unsigned int tcplen)
1008{ 1008{
1009 struct scatterlist sg[4];
1010 __u16 data_len;
1011 int block = 0;
1012 __sum16 old_checksum;
1013 struct tcp_md5sig_pool *hp; 1009 struct tcp_md5sig_pool *hp;
1014 struct tcp4_pseudohdr *bp; 1010 struct tcp4_pseudohdr *bp;
1015 struct hash_desc *desc;
1016 int err; 1011 int err;
1017 unsigned int nbytes = 0;
1018 1012
1019 /* 1013 /*
1020 * Okay, so RFC2385 is turned on for this connection, 1014 * Okay, so RFC2385 is turned on for this connection,
@@ -1026,10 +1020,9 @@ static int tcp_v4_do_calc_md5_hash(char *md5_hash, struct tcp_md5sig_key *key,
1026 goto clear_hash_noput; 1020 goto clear_hash_noput;
1027 1021
1028 bp = &hp->md5_blk.ip4; 1022 bp = &hp->md5_blk.ip4;
1029 desc = &hp->md5_desc;
1030 1023
1031 /* 1024 /*
1032 * 1. the TCP pseudo-header (in the order: source IP address, 1025 * The TCP pseudo-header (in the order: source IP address,
1033 * destination IP address, zero-padded protocol number, and 1026 * destination IP address, zero-padded protocol number, and
1034 * segment length) 1027 * segment length)
1035 */ 1028 */
@@ -1039,50 +1032,13 @@ static int tcp_v4_do_calc_md5_hash(char *md5_hash, struct tcp_md5sig_key *key,
1039 bp->protocol = IPPROTO_TCP; 1032 bp->protocol = IPPROTO_TCP;
1040 bp->len = htons(tcplen); 1033 bp->len = htons(tcplen);
1041 1034
1042 sg_init_table(sg, 4); 1035 err = tcp_calc_md5_hash(md5_hash, key, sizeof(*bp),
1043 1036 th, tcplen, hp);
1044 sg_set_buf(&sg[block++], bp, sizeof(*bp));
1045 nbytes += sizeof(*bp);
1046
1047 /* 2. the TCP header, excluding options, and assuming a
1048 * checksum of zero/
1049 */
1050 old_checksum = th->check;
1051 th->check = 0;
1052 sg_set_buf(&sg[block++], th, sizeof(struct tcphdr));
1053 nbytes += sizeof(struct tcphdr);
1054
1055 /* 3. the TCP segment data (if any) */
1056 data_len = tcplen - (th->doff << 2);
1057 if (data_len > 0) {
1058 unsigned char *data = (unsigned char *)th + (th->doff << 2);
1059 sg_set_buf(&sg[block++], data, data_len);
1060 nbytes += data_len;
1061 }
1062
1063 /* 4. an independently-specified key or password, known to both
1064 * TCPs and presumably connection-specific
1065 */
1066 sg_set_buf(&sg[block++], key->key, key->keylen);
1067 nbytes += key->keylen;
1068
1069 sg_mark_end(&sg[block - 1]);
1070
1071 /* Now store the Hash into the packet */
1072 err = crypto_hash_init(desc);
1073 if (err)
1074 goto clear_hash;
1075 err = crypto_hash_update(desc, sg, nbytes);
1076 if (err)
1077 goto clear_hash;
1078 err = crypto_hash_final(desc, md5_hash);
1079 if (err) 1037 if (err)
1080 goto clear_hash; 1038 goto clear_hash;
1081 1039
1082 /* Reset header, and free up the crypto */ 1040 /* Free up the crypto pool */
1083 tcp_put_md5sig_pool(); 1041 tcp_put_md5sig_pool();
1084 th->check = old_checksum;
1085
1086out: 1042out:
1087 return 0; 1043 return 0;
1088clear_hash: 1044clear_hash:
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index 334d21c23da9..0ae0311082fb 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -738,23 +738,17 @@ static int tcp_v6_do_calc_md5_hash(char *md5_hash, struct tcp_md5sig_key *key,
738 struct in6_addr *daddr, 738 struct in6_addr *daddr,
739 struct tcphdr *th, unsigned int tcplen) 739 struct tcphdr *th, unsigned int tcplen)
740{ 740{
741 struct scatterlist sg[4];
742 __u16 data_len;
743 int block = 0;
744 __sum16 cksum;
745 struct tcp_md5sig_pool *hp; 741 struct tcp_md5sig_pool *hp;
746 struct tcp6_pseudohdr *bp; 742 struct tcp6_pseudohdr *bp;
747 struct hash_desc *desc;
748 int err; 743 int err;
749 unsigned int nbytes = 0;
750 744
751 hp = tcp_get_md5sig_pool(); 745 hp = tcp_get_md5sig_pool();
752 if (!hp) { 746 if (!hp) {
753 printk(KERN_WARNING "%s(): hash pool not found...\n", __func__); 747 printk(KERN_WARNING "%s(): hash pool not found...\n", __func__);
754 goto clear_hash_noput; 748 goto clear_hash_noput;
755 } 749 }
750
756 bp = &hp->md5_blk.ip6; 751 bp = &hp->md5_blk.ip6;
757 desc = &hp->md5_desc;
758 752
759 /* 1. TCP pseudo-header (RFC2460) */ 753 /* 1. TCP pseudo-header (RFC2460) */
760 ipv6_addr_copy(&bp->saddr, saddr); 754 ipv6_addr_copy(&bp->saddr, saddr);
@@ -762,51 +756,14 @@ static int tcp_v6_do_calc_md5_hash(char *md5_hash, struct tcp_md5sig_key *key,
762 bp->len = htonl(tcplen); 756 bp->len = htonl(tcplen);
763 bp->protocol = htonl(IPPROTO_TCP); 757 bp->protocol = htonl(IPPROTO_TCP);
764 758
765 sg_init_table(sg, 4); 759 err = tcp_calc_md5_hash(md5_hash, key, sizeof(*bp),
766 760 th, tcplen, hp);
767 sg_set_buf(&sg[block++], bp, sizeof(*bp));
768 nbytes += sizeof(*bp);
769
770 /* 2. TCP header, excluding options */
771 cksum = th->check;
772 th->check = 0;
773 sg_set_buf(&sg[block++], th, sizeof(*th));
774 nbytes += sizeof(*th);
775
776 /* 3. TCP segment data (if any) */
777 data_len = tcplen - (th->doff << 2);
778 if (data_len > 0) {
779 u8 *data = (u8 *)th + (th->doff << 2);
780 sg_set_buf(&sg[block++], data, data_len);
781 nbytes += data_len;
782 }
783
784 /* 4. shared key */
785 sg_set_buf(&sg[block++], key->key, key->keylen);
786 nbytes += key->keylen;
787
788 sg_mark_end(&sg[block - 1]);
789 761
790 /* Now store the hash into the packet */ 762 if (err)
791 err = crypto_hash_init(desc);
792 if (err) {
793 printk(KERN_WARNING "%s(): hash_init failed\n", __func__);
794 goto clear_hash;
795 }
796 err = crypto_hash_update(desc, sg, nbytes);
797 if (err) {
798 printk(KERN_WARNING "%s(): hash_update failed\n", __func__);
799 goto clear_hash;
800 }
801 err = crypto_hash_final(desc, md5_hash);
802 if (err) {
803 printk(KERN_WARNING "%s(): hash_final failed\n", __func__);
804 goto clear_hash; 763 goto clear_hash;
805 }
806 764
807 /* Reset header, and free up the crypto */ 765 /* Free up the crypto pool */
808 tcp_put_md5sig_pool(); 766 tcp_put_md5sig_pool();
809 th->check = cksum;
810out: 767out:
811 return 0; 768 return 0;
812clear_hash: 769clear_hash: