diff options
Diffstat (limited to 'net/ipv4/tcp.c')
-rw-r--r-- | net/ipv4/tcp.c | 127 |
1 files changed, 57 insertions, 70 deletions
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 827e6132af5f..0b491bf03db4 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c | |||
@@ -2465,76 +2465,6 @@ static unsigned long tcp_md5sig_users; | |||
2465 | static struct tcp_md5sig_pool **tcp_md5sig_pool; | 2465 | static struct tcp_md5sig_pool **tcp_md5sig_pool; |
2466 | static DEFINE_SPINLOCK(tcp_md5sig_pool_lock); | 2466 | static DEFINE_SPINLOCK(tcp_md5sig_pool_lock); |
2467 | 2467 | ||
2468 | int tcp_calc_md5_hash(char *md5_hash, struct tcp_md5sig_key *key, | ||
2469 | int bplen, | ||
2470 | struct tcphdr *th, unsigned int tcplen, | ||
2471 | struct tcp_md5sig_pool *hp) | ||
2472 | { | ||
2473 | struct scatterlist sg[4]; | ||
2474 | __u16 data_len; | ||
2475 | int block = 0; | ||
2476 | __sum16 cksum; | ||
2477 | struct hash_desc *desc = &hp->md5_desc; | ||
2478 | int err; | ||
2479 | unsigned int nbytes = 0; | ||
2480 | |||
2481 | sg_init_table(sg, 4); | ||
2482 | |||
2483 | /* 1. The TCP pseudo-header */ | ||
2484 | sg_set_buf(&sg[block++], &hp->md5_blk, bplen); | ||
2485 | nbytes += bplen; | ||
2486 | |||
2487 | /* 2. The TCP header, excluding options, and assuming a | ||
2488 | * checksum of zero | ||
2489 | */ | ||
2490 | cksum = th->check; | ||
2491 | th->check = 0; | ||
2492 | sg_set_buf(&sg[block++], th, sizeof(*th)); | ||
2493 | nbytes += sizeof(*th); | ||
2494 | |||
2495 | /* 3. The TCP segment data (if any) */ | ||
2496 | data_len = tcplen - (th->doff << 2); | ||
2497 | if (data_len > 0) { | ||
2498 | u8 *data = (u8 *)th + (th->doff << 2); | ||
2499 | sg_set_buf(&sg[block++], data, data_len); | ||
2500 | nbytes += data_len; | ||
2501 | } | ||
2502 | |||
2503 | /* 4. an independently-specified key or password, known to both | ||
2504 | * TCPs and presumably connection-specific | ||
2505 | */ | ||
2506 | sg_set_buf(&sg[block++], key->key, key->keylen); | ||
2507 | nbytes += key->keylen; | ||
2508 | |||
2509 | sg_mark_end(&sg[block - 1]); | ||
2510 | |||
2511 | /* Now store the hash into the packet */ | ||
2512 | err = crypto_hash_init(desc); | ||
2513 | if (err) { | ||
2514 | if (net_ratelimit()) | ||
2515 | printk(KERN_WARNING "%s(): hash_init failed\n", __func__); | ||
2516 | return -1; | ||
2517 | } | ||
2518 | err = crypto_hash_update(desc, sg, nbytes); | ||
2519 | if (err) { | ||
2520 | if (net_ratelimit()) | ||
2521 | printk(KERN_WARNING "%s(): hash_update failed\n", __func__); | ||
2522 | return -1; | ||
2523 | } | ||
2524 | err = crypto_hash_final(desc, md5_hash); | ||
2525 | if (err) { | ||
2526 | if (net_ratelimit()) | ||
2527 | printk(KERN_WARNING "%s(): hash_final failed\n", __func__); | ||
2528 | return -1; | ||
2529 | } | ||
2530 | |||
2531 | /* Reset header */ | ||
2532 | th->check = cksum; | ||
2533 | |||
2534 | return 0; | ||
2535 | } | ||
2536 | EXPORT_SYMBOL(tcp_calc_md5_hash); | ||
2537 | |||
2538 | static void __tcp_free_md5sig_pool(struct tcp_md5sig_pool **pool) | 2468 | static void __tcp_free_md5sig_pool(struct tcp_md5sig_pool **pool) |
2539 | { | 2469 | { |
2540 | int cpu; | 2470 | int cpu; |
@@ -2658,6 +2588,63 @@ void __tcp_put_md5sig_pool(void) | |||
2658 | } | 2588 | } |
2659 | 2589 | ||
2660 | EXPORT_SYMBOL(__tcp_put_md5sig_pool); | 2590 | EXPORT_SYMBOL(__tcp_put_md5sig_pool); |
2591 | |||
2592 | int tcp_md5_hash_header(struct tcp_md5sig_pool *hp, | ||
2593 | struct tcphdr *th) | ||
2594 | { | ||
2595 | struct scatterlist sg; | ||
2596 | int err; | ||
2597 | |||
2598 | __sum16 old_checksum = th->check; | ||
2599 | th->check = 0; | ||
2600 | /* options aren't included in the hash */ | ||
2601 | sg_init_one(&sg, th, sizeof(struct tcphdr)); | ||
2602 | err = crypto_hash_update(&hp->md5_desc, &sg, sizeof(struct tcphdr)); | ||
2603 | th->check = old_checksum; | ||
2604 | return err; | ||
2605 | } | ||
2606 | |||
2607 | EXPORT_SYMBOL(tcp_md5_hash_header); | ||
2608 | |||
2609 | int tcp_md5_hash_skb_data(struct tcp_md5sig_pool *hp, | ||
2610 | struct sk_buff *skb, unsigned header_len) | ||
2611 | { | ||
2612 | struct scatterlist sg; | ||
2613 | const struct tcphdr *tp = tcp_hdr(skb); | ||
2614 | struct hash_desc *desc = &hp->md5_desc; | ||
2615 | unsigned i; | ||
2616 | const unsigned head_data_len = skb_headlen(skb) > header_len ? | ||
2617 | skb_headlen(skb) - header_len : 0; | ||
2618 | const struct skb_shared_info *shi = skb_shinfo(skb); | ||
2619 | |||
2620 | sg_init_table(&sg, 1); | ||
2621 | |||
2622 | sg_set_buf(&sg, ((u8 *) tp) + header_len, head_data_len); | ||
2623 | if (crypto_hash_update(desc, &sg, head_data_len)) | ||
2624 | return 1; | ||
2625 | |||
2626 | for (i = 0; i < shi->nr_frags; ++i) { | ||
2627 | const struct skb_frag_struct *f = &shi->frags[i]; | ||
2628 | sg_set_page(&sg, f->page, f->size, f->page_offset); | ||
2629 | if (crypto_hash_update(desc, &sg, f->size)) | ||
2630 | return 1; | ||
2631 | } | ||
2632 | |||
2633 | return 0; | ||
2634 | } | ||
2635 | |||
2636 | EXPORT_SYMBOL(tcp_md5_hash_skb_data); | ||
2637 | |||
2638 | int tcp_md5_hash_key(struct tcp_md5sig_pool *hp, struct tcp_md5sig_key *key) | ||
2639 | { | ||
2640 | struct scatterlist sg; | ||
2641 | |||
2642 | sg_init_one(&sg, key->key, key->keylen); | ||
2643 | return crypto_hash_update(&hp->md5_desc, &sg, key->keylen); | ||
2644 | } | ||
2645 | |||
2646 | EXPORT_SYMBOL(tcp_md5_hash_key); | ||
2647 | |||
2661 | #endif | 2648 | #endif |
2662 | 2649 | ||
2663 | void tcp_done(struct sock *sk) | 2650 | void tcp_done(struct sock *sk) |