diff options
author | David S. Miller <davem@davemloft.net> | 2008-06-12 01:33:59 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-06-12 01:33:59 -0400 |
commit | e6e30add6bd8115af108de2a13ec82d997a55777 (patch) | |
tree | 558b4d1c3ac369805aa9c57abca710bdf52aff75 /net/ipv4/tcp.c | |
parent | d4c3c0753594adaafbcb77a086f013f1d847b3f0 (diff) | |
parent | 9501f9722922f2e80e1f9dc6682311d65c2b5690 (diff) |
Merge branch 'net-next-2.6-misc-20080612a' of git://git.linux-ipv6.org/gitroot/yoshfuji/linux-2.6-next
Diffstat (limited to 'net/ipv4/tcp.c')
-rw-r--r-- | net/ipv4/tcp.c | 70 |
1 files changed, 70 insertions, 0 deletions
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index ad66b09e0bc..6d30ca559c6 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c | |||
@@ -2457,6 +2457,76 @@ static unsigned long tcp_md5sig_users; | |||
2457 | static struct tcp_md5sig_pool **tcp_md5sig_pool; | 2457 | static struct tcp_md5sig_pool **tcp_md5sig_pool; |
2458 | static DEFINE_SPINLOCK(tcp_md5sig_pool_lock); | 2458 | static DEFINE_SPINLOCK(tcp_md5sig_pool_lock); |
2459 | 2459 | ||
2460 | int tcp_calc_md5_hash(char *md5_hash, struct tcp_md5sig_key *key, | ||
2461 | int bplen, | ||
2462 | struct tcphdr *th, unsigned int tcplen, | ||
2463 | struct tcp_md5sig_pool *hp) | ||
2464 | { | ||
2465 | struct scatterlist sg[4]; | ||
2466 | __u16 data_len; | ||
2467 | int block = 0; | ||
2468 | __sum16 cksum; | ||
2469 | struct hash_desc *desc = &hp->md5_desc; | ||
2470 | int err; | ||
2471 | unsigned int nbytes = 0; | ||
2472 | |||
2473 | sg_init_table(sg, 4); | ||
2474 | |||
2475 | /* 1. The TCP pseudo-header */ | ||
2476 | sg_set_buf(&sg[block++], &hp->md5_blk, bplen); | ||
2477 | nbytes += bplen; | ||
2478 | |||
2479 | /* 2. The TCP header, excluding options, and assuming a | ||
2480 | * checksum of zero | ||
2481 | */ | ||
2482 | cksum = th->check; | ||
2483 | th->check = 0; | ||
2484 | sg_set_buf(&sg[block++], th, sizeof(*th)); | ||
2485 | nbytes += sizeof(*th); | ||
2486 | |||
2487 | /* 3. The TCP segment data (if any) */ | ||
2488 | data_len = tcplen - (th->doff << 2); | ||
2489 | if (data_len > 0) { | ||
2490 | u8 *data = (u8 *)th + (th->doff << 2); | ||
2491 | sg_set_buf(&sg[block++], data, data_len); | ||
2492 | nbytes += data_len; | ||
2493 | } | ||
2494 | |||
2495 | /* 4. an independently-specified key or password, known to both | ||
2496 | * TCPs and presumably connection-specific | ||
2497 | */ | ||
2498 | sg_set_buf(&sg[block++], key->key, key->keylen); | ||
2499 | nbytes += key->keylen; | ||
2500 | |||
2501 | sg_mark_end(&sg[block - 1]); | ||
2502 | |||
2503 | /* Now store the hash into the packet */ | ||
2504 | err = crypto_hash_init(desc); | ||
2505 | if (err) { | ||
2506 | if (net_ratelimit()) | ||
2507 | printk(KERN_WARNING "%s(): hash_init failed\n", __func__); | ||
2508 | return -1; | ||
2509 | } | ||
2510 | err = crypto_hash_update(desc, sg, nbytes); | ||
2511 | if (err) { | ||
2512 | if (net_ratelimit()) | ||
2513 | printk(KERN_WARNING "%s(): hash_update failed\n", __func__); | ||
2514 | return -1; | ||
2515 | } | ||
2516 | err = crypto_hash_final(desc, md5_hash); | ||
2517 | if (err) { | ||
2518 | if (net_ratelimit()) | ||
2519 | printk(KERN_WARNING "%s(): hash_final failed\n", __func__); | ||
2520 | return -1; | ||
2521 | } | ||
2522 | |||
2523 | /* Reset header */ | ||
2524 | th->check = cksum; | ||
2525 | |||
2526 | return 0; | ||
2527 | } | ||
2528 | EXPORT_SYMBOL(tcp_calc_md5_hash); | ||
2529 | |||
2460 | static void __tcp_free_md5sig_pool(struct tcp_md5sig_pool **pool) | 2530 | static void __tcp_free_md5sig_pool(struct tcp_md5sig_pool **pool) |
2461 | { | 2531 | { |
2462 | int cpu; | 2532 | int cpu; |