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