diff options
Diffstat (limited to 'net/ipv4/tcp.c')
-rw-r--r-- | net/ipv4/tcp.c | 72 |
1 files changed, 70 insertions, 2 deletions
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 1d723de18686..56a133c61452 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> |
@@ -2467,6 +2465,76 @@ static unsigned long tcp_md5sig_users; | |||
2467 | static struct tcp_md5sig_pool **tcp_md5sig_pool; | 2465 | static struct tcp_md5sig_pool **tcp_md5sig_pool; |
2468 | static DEFINE_SPINLOCK(tcp_md5sig_pool_lock); | 2466 | static DEFINE_SPINLOCK(tcp_md5sig_pool_lock); |
2469 | 2467 | ||
2468 | int tcp_calc_md5_hash(char *md5_hash, struct tcp_md5sig_key *key, | ||
2469 | int bplen, | ||
2470 | struct tcphdr *th, unsigned int tcplen, | ||
2471 | struct tcp_md5sig_pool *hp) | ||
2472 | { | ||
2473 | struct scatterlist sg[4]; | ||
2474 | __u16 data_len; | ||
2475 | int block = 0; | ||
2476 | __sum16 cksum; | ||
2477 | struct hash_desc *desc = &hp->md5_desc; | ||
2478 | int err; | ||
2479 | unsigned int nbytes = 0; | ||
2480 | |||
2481 | sg_init_table(sg, 4); | ||
2482 | |||
2483 | /* 1. The TCP pseudo-header */ | ||
2484 | sg_set_buf(&sg[block++], &hp->md5_blk, bplen); | ||
2485 | nbytes += bplen; | ||
2486 | |||
2487 | /* 2. The TCP header, excluding options, and assuming a | ||
2488 | * checksum of zero | ||
2489 | */ | ||
2490 | cksum = th->check; | ||
2491 | th->check = 0; | ||
2492 | sg_set_buf(&sg[block++], th, sizeof(*th)); | ||
2493 | nbytes += sizeof(*th); | ||
2494 | |||
2495 | /* 3. The TCP segment data (if any) */ | ||
2496 | data_len = tcplen - (th->doff << 2); | ||
2497 | if (data_len > 0) { | ||
2498 | u8 *data = (u8 *)th + (th->doff << 2); | ||
2499 | sg_set_buf(&sg[block++], data, data_len); | ||
2500 | nbytes += data_len; | ||
2501 | } | ||
2502 | |||
2503 | /* 4. an independently-specified key or password, known to both | ||
2504 | * TCPs and presumably connection-specific | ||
2505 | */ | ||
2506 | sg_set_buf(&sg[block++], key->key, key->keylen); | ||
2507 | nbytes += key->keylen; | ||
2508 | |||
2509 | sg_mark_end(&sg[block - 1]); | ||
2510 | |||
2511 | /* Now store the hash into the packet */ | ||
2512 | err = crypto_hash_init(desc); | ||
2513 | if (err) { | ||
2514 | if (net_ratelimit()) | ||
2515 | printk(KERN_WARNING "%s(): hash_init failed\n", __func__); | ||
2516 | return -1; | ||
2517 | } | ||
2518 | err = crypto_hash_update(desc, sg, nbytes); | ||
2519 | if (err) { | ||
2520 | if (net_ratelimit()) | ||
2521 | printk(KERN_WARNING "%s(): hash_update failed\n", __func__); | ||
2522 | return -1; | ||
2523 | } | ||
2524 | err = crypto_hash_final(desc, md5_hash); | ||
2525 | if (err) { | ||
2526 | if (net_ratelimit()) | ||
2527 | printk(KERN_WARNING "%s(): hash_final failed\n", __func__); | ||
2528 | return -1; | ||
2529 | } | ||
2530 | |||
2531 | /* Reset header */ | ||
2532 | th->check = cksum; | ||
2533 | |||
2534 | return 0; | ||
2535 | } | ||
2536 | EXPORT_SYMBOL(tcp_calc_md5_hash); | ||
2537 | |||
2470 | static void __tcp_free_md5sig_pool(struct tcp_md5sig_pool **pool) | 2538 | static void __tcp_free_md5sig_pool(struct tcp_md5sig_pool **pool) |
2471 | { | 2539 | { |
2472 | int cpu; | 2540 | int cpu; |