diff options
Diffstat (limited to 'net')
-rw-r--r-- | net/ipv4/tcp.c | 70 | ||||
-rw-r--r-- | net/ipv4/tcp_ipv4.c | 52 | ||||
-rw-r--r-- | net/ipv6/tcp_ipv6.c | 53 |
3 files changed, 79 insertions, 96 deletions
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; | |||
2459 | static struct tcp_md5sig_pool **tcp_md5sig_pool; | 2459 | static struct tcp_md5sig_pool **tcp_md5sig_pool; |
2460 | static DEFINE_SPINLOCK(tcp_md5sig_pool_lock); | 2460 | static DEFINE_SPINLOCK(tcp_md5sig_pool_lock); |
2461 | 2461 | ||
2462 | int 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 | } | ||
2530 | EXPORT_SYMBOL(tcp_calc_md5_hash); | ||
2531 | |||
2462 | static void __tcp_free_md5sig_pool(struct tcp_md5sig_pool **pool) | 2532 | static 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 | |||
1086 | out: | 1042 | out: |
1087 | return 0; | 1043 | return 0; |
1088 | clear_hash: | 1044 | clear_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; | ||
810 | out: | 767 | out: |
811 | return 0; | 768 | return 0; |
812 | clear_hash: | 769 | clear_hash: |