aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4/tcp.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv4/tcp.c')
-rw-r--r--net/ipv4/tcp.c72
1 files changed, 70 insertions, 2 deletions
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index fc54a48fde1e..cf0850c068f5 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -5,8 +5,6 @@
5 * 5 *
6 * Implementation of the Transmission Control Protocol(TCP). 6 * Implementation of the Transmission Control Protocol(TCP).
7 * 7 *
8 * Version: $Id: tcp.c,v 1.216 2002/02/01 22:01:04 davem Exp $
9 *
10 * Authors: Ross Biro 8 * Authors: Ross Biro
11 * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> 9 * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
12 * Mark Evans, <evansmp@uhura.aston.ac.uk> 10 * Mark Evans, <evansmp@uhura.aston.ac.uk>
@@ -2463,6 +2461,76 @@ static unsigned long tcp_md5sig_users;
2463static struct tcp_md5sig_pool **tcp_md5sig_pool; 2461static struct tcp_md5sig_pool **tcp_md5sig_pool;
2464static DEFINE_SPINLOCK(tcp_md5sig_pool_lock); 2462static DEFINE_SPINLOCK(tcp_md5sig_pool_lock);
2465 2463
2464int tcp_calc_md5_hash(char *md5_hash, struct tcp_md5sig_key *key,
2465 int bplen,
2466 struct tcphdr *th, unsigned int tcplen,
2467 struct tcp_md5sig_pool *hp)
2468{
2469 struct scatterlist sg[4];
2470 __u16 data_len;
2471 int block = 0;
2472 __sum16 cksum;
2473 struct hash_desc *desc = &hp->md5_desc;
2474 int err;
2475 unsigned int nbytes = 0;
2476
2477 sg_init_table(sg, 4);
2478
2479 /* 1. The TCP pseudo-header */
2480 sg_set_buf(&sg[block++], &hp->md5_blk, bplen);
2481 nbytes += bplen;
2482
2483 /* 2. The TCP header, excluding options, and assuming a
2484 * checksum of zero
2485 */
2486 cksum = th->check;
2487 th->check = 0;
2488 sg_set_buf(&sg[block++], th, sizeof(*th));
2489 nbytes += sizeof(*th);
2490
2491 /* 3. The TCP segment data (if any) */
2492 data_len = tcplen - (th->doff << 2);
2493 if (data_len > 0) {
2494 u8 *data = (u8 *)th + (th->doff << 2);
2495 sg_set_buf(&sg[block++], data, data_len);
2496 nbytes += data_len;
2497 }
2498
2499 /* 4. an independently-specified key or password, known to both
2500 * TCPs and presumably connection-specific
2501 */
2502 sg_set_buf(&sg[block++], key->key, key->keylen);
2503 nbytes += key->keylen;
2504
2505 sg_mark_end(&sg[block - 1]);
2506
2507 /* Now store the hash into the packet */
2508 err = crypto_hash_init(desc);
2509 if (err) {
2510 if (net_ratelimit())
2511 printk(KERN_WARNING "%s(): hash_init failed\n", __func__);
2512 return -1;
2513 }
2514 err = crypto_hash_update(desc, sg, nbytes);
2515 if (err) {
2516 if (net_ratelimit())
2517 printk(KERN_WARNING "%s(): hash_update failed\n", __func__);
2518 return -1;
2519 }
2520 err = crypto_hash_final(desc, md5_hash);
2521 if (err) {
2522 if (net_ratelimit())
2523 printk(KERN_WARNING "%s(): hash_final failed\n", __func__);
2524 return -1;
2525 }
2526
2527 /* Reset header */
2528 th->check = cksum;
2529
2530 return 0;
2531}
2532EXPORT_SYMBOL(tcp_calc_md5_hash);
2533
2466static void __tcp_free_md5sig_pool(struct tcp_md5sig_pool **pool) 2534static void __tcp_free_md5sig_pool(struct tcp_md5sig_pool **pool)
2467{ 2535{
2468 int cpu; 2536 int cpu;