aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4/tcp.c
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2008-06-12 01:33:59 -0400
committerDavid S. Miller <davem@davemloft.net>2008-06-12 01:33:59 -0400
commite6e30add6bd8115af108de2a13ec82d997a55777 (patch)
tree558b4d1c3ac369805aa9c57abca710bdf52aff75 /net/ipv4/tcp.c
parentd4c3c0753594adaafbcb77a086f013f1d847b3f0 (diff)
parent9501f9722922f2e80e1f9dc6682311d65c2b5690 (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.c70
1 files changed, 70 insertions, 0 deletions
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index ad66b09e0bcd..6d30ca559c64 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -2457,6 +2457,76 @@ static unsigned long tcp_md5sig_users;
2457static struct tcp_md5sig_pool **tcp_md5sig_pool; 2457static struct tcp_md5sig_pool **tcp_md5sig_pool;
2458static DEFINE_SPINLOCK(tcp_md5sig_pool_lock); 2458static DEFINE_SPINLOCK(tcp_md5sig_pool_lock);
2459 2459
2460int 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}
2528EXPORT_SYMBOL(tcp_calc_md5_hash);
2529
2460static void __tcp_free_md5sig_pool(struct tcp_md5sig_pool **pool) 2530static void __tcp_free_md5sig_pool(struct tcp_md5sig_pool **pool)
2461{ 2531{
2462 int cpu; 2532 int cpu;