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) |
