aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4/tcp.c
diff options
context:
space:
mode:
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;