aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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: