aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4/tcp.c
diff options
context:
space:
mode:
authorYOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>2008-04-17 00:19:16 -0400
committerYOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>2008-06-11 13:38:20 -0400
commit8d26d76dd4a4c87ef037a44a42a0608ffc730199 (patch)
tree884ff53a83e460aa3f1837cc336a5a34f364156e /net/ipv4/tcp.c
parent076fb7223357769c39f3ddf900bba6752369c76a (diff)
tcp md5sig: Share most of hash calcucaltion bits between IPv4 and IPv6.
We can share most part of the hash calculation code because the only difference between IPv4 and IPv6 is their pseudo headers. Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
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 ab66683b8043..6efbae0e5512 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -2459,6 +2459,76 @@ static unsigned long tcp_md5sig_users;
2459static struct tcp_md5sig_pool **tcp_md5sig_pool; 2459static struct tcp_md5sig_pool **tcp_md5sig_pool;
2460static DEFINE_SPINLOCK(tcp_md5sig_pool_lock); 2460static DEFINE_SPINLOCK(tcp_md5sig_pool_lock);
2461 2461
2462int tcp_calc_md5_hash(char *md5_hash, struct tcp_md5sig_key *key,
2463 int bplen,
2464 struct tcphdr *th, unsigned int tcplen,
2465 struct tcp_md5sig_pool *hp)
2466{
2467 struct scatterlist sg[4];
2468 __u16 data_len;
2469 int block = 0;
2470 __sum16 cksum;
2471 struct hash_desc *desc = &hp->md5_desc;
2472 int err;
2473 unsigned int nbytes = 0;
2474
2475 sg_init_table(sg, 4);
2476
2477 /* 1. The TCP pseudo-header */
2478 sg_set_buf(&sg[block++], &hp->md5_blk, bplen);
2479 nbytes += bplen;
2480
2481 /* 2. The TCP header, excluding options, and assuming a
2482 * checksum of zero
2483 */
2484 cksum = th->check;
2485 th->check = 0;
2486 sg_set_buf(&sg[block++], th, sizeof(*th));
2487 nbytes += sizeof(*th);
2488
2489 /* 3. The TCP segment data (if any) */
2490 data_len = tcplen - (th->doff << 2);
2491 if (data_len > 0) {
2492 u8 *data = (u8 *)th + (th->doff << 2);
2493 sg_set_buf(&sg[block++], data, data_len);
2494 nbytes += data_len;
2495 }
2496
2497 /* 4. an independently-specified key or password, known to both
2498 * TCPs and presumably connection-specific
2499 */
2500 sg_set_buf(&sg[block++], key->key, key->keylen);
2501 nbytes += key->keylen;
2502
2503 sg_mark_end(&sg[block - 1]);
2504
2505 /* Now store the hash into the packet */
2506 err = crypto_hash_init(desc);
2507 if (err) {
2508 if (net_ratelimit())
2509 printk(KERN_WARNING "%s(): hash_init failed\n", __func__);
2510 return -1;
2511 }
2512 err = crypto_hash_update(desc, sg, nbytes);
2513 if (err) {
2514 if (net_ratelimit())
2515 printk(KERN_WARNING "%s(): hash_update failed\n", __func__);
2516 return -1;
2517 }
2518 err = crypto_hash_final(desc, md5_hash);
2519 if (err) {
2520 if (net_ratelimit())
2521 printk(KERN_WARNING "%s(): hash_final failed\n", __func__);
2522 return -1;
2523 }
2524
2525 /* Reset header */
2526 th->check = cksum;
2527
2528 return 0;
2529}
2530EXPORT_SYMBOL(tcp_calc_md5_hash);
2531
2462static void __tcp_free_md5sig_pool(struct tcp_md5sig_pool **pool) 2532static void __tcp_free_md5sig_pool(struct tcp_md5sig_pool **pool)
2463{ 2533{
2464 int cpu; 2534 int cpu;