diff options
| -rw-r--r-- | include/net/tcp.h | 29 | ||||
| -rw-r--r-- | net/ipv4/tcp.c | 127 | ||||
| -rw-r--r-- | net/ipv4/tcp_ipv4.c | 140 | ||||
| -rw-r--r-- | net/ipv4/tcp_output.c | 14 | ||||
| -rw-r--r-- | net/ipv6/tcp_ipv6.c | 127 |
5 files changed, 242 insertions, 195 deletions
diff --git a/include/net/tcp.h b/include/net/tcp.h index 92d7b551dc55..31f5bbfc59bc 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h | |||
| @@ -1112,20 +1112,12 @@ struct tcp_md5sig_pool { | |||
| 1112 | #define TCP_MD5SIG_MAXKEYS (~(u32)0) /* really?! */ | 1112 | #define TCP_MD5SIG_MAXKEYS (~(u32)0) /* really?! */ |
| 1113 | 1113 | ||
| 1114 | /* - functions */ | 1114 | /* - functions */ |
| 1115 | extern int tcp_calc_md5_hash(char *md5_hash, | 1115 | extern int tcp_v4_md5_hash_skb(char *md5_hash, |
| 1116 | struct tcp_md5sig_key *key, | 1116 | struct tcp_md5sig_key *key, |
| 1117 | int bplen, | 1117 | struct sock *sk, |
| 1118 | struct tcphdr *th, | 1118 | struct request_sock *req, |
| 1119 | unsigned int tcplen, | 1119 | struct sk_buff *skb); |
| 1120 | struct tcp_md5sig_pool *hp); | 1120 | |
| 1121 | |||
| 1122 | extern int tcp_v4_calc_md5_hash(char *md5_hash, | ||
| 1123 | struct tcp_md5sig_key *key, | ||
| 1124 | struct sock *sk, | ||
| 1125 | struct dst_entry *dst, | ||
| 1126 | struct request_sock *req, | ||
| 1127 | struct tcphdr *th, | ||
| 1128 | unsigned int tcplen); | ||
| 1129 | extern struct tcp_md5sig_key *tcp_v4_md5_lookup(struct sock *sk, | 1121 | extern struct tcp_md5sig_key *tcp_v4_md5_lookup(struct sock *sk, |
| 1130 | struct sock *addr_sk); | 1122 | struct sock *addr_sk); |
| 1131 | 1123 | ||
| @@ -1152,6 +1144,11 @@ extern void tcp_free_md5sig_pool(void); | |||
| 1152 | 1144 | ||
| 1153 | extern struct tcp_md5sig_pool *__tcp_get_md5sig_pool(int cpu); | 1145 | extern struct tcp_md5sig_pool *__tcp_get_md5sig_pool(int cpu); |
| 1154 | extern void __tcp_put_md5sig_pool(void); | 1146 | extern void __tcp_put_md5sig_pool(void); |
| 1147 | extern int tcp_md5_hash_header(struct tcp_md5sig_pool *, struct tcphdr *); | ||
| 1148 | extern int tcp_md5_hash_skb_data(struct tcp_md5sig_pool *, struct sk_buff *, | ||
| 1149 | unsigned header_len); | ||
| 1150 | extern int tcp_md5_hash_key(struct tcp_md5sig_pool *hp, | ||
| 1151 | struct tcp_md5sig_key *key); | ||
| 1155 | 1152 | ||
| 1156 | static inline | 1153 | static inline |
| 1157 | struct tcp_md5sig_pool *tcp_get_md5sig_pool(void) | 1154 | struct tcp_md5sig_pool *tcp_get_md5sig_pool(void) |
| @@ -1381,10 +1378,8 @@ struct tcp_sock_af_ops { | |||
| 1381 | int (*calc_md5_hash) (char *location, | 1378 | int (*calc_md5_hash) (char *location, |
| 1382 | struct tcp_md5sig_key *md5, | 1379 | struct tcp_md5sig_key *md5, |
| 1383 | struct sock *sk, | 1380 | struct sock *sk, |
| 1384 | struct dst_entry *dst, | ||
| 1385 | struct request_sock *req, | 1381 | struct request_sock *req, |
| 1386 | struct tcphdr *th, | 1382 | struct sk_buff *skb); |
| 1387 | unsigned int len); | ||
| 1388 | int (*md5_add) (struct sock *sk, | 1383 | int (*md5_add) (struct sock *sk, |
| 1389 | struct sock *addr_sk, | 1384 | struct sock *addr_sk, |
| 1390 | u8 *newkey, | 1385 | u8 *newkey, |
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) |
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 29adc668ad51..5400d75ff17a 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c | |||
| @@ -87,9 +87,8 @@ int sysctl_tcp_low_latency __read_mostly; | |||
| 87 | #ifdef CONFIG_TCP_MD5SIG | 87 | #ifdef CONFIG_TCP_MD5SIG |
| 88 | static struct tcp_md5sig_key *tcp_v4_md5_do_lookup(struct sock *sk, | 88 | static struct tcp_md5sig_key *tcp_v4_md5_do_lookup(struct sock *sk, |
| 89 | __be32 addr); | 89 | __be32 addr); |
| 90 | static int tcp_v4_do_calc_md5_hash(char *md5_hash, struct tcp_md5sig_key *key, | 90 | static int tcp_v4_md5_hash_hdr(char *md5_hash, struct tcp_md5sig_key *key, |
| 91 | __be32 saddr, __be32 daddr, | 91 | __be32 daddr, __be32 saddr, struct tcphdr *th); |
| 92 | struct tcphdr *th, unsigned int tcplen); | ||
| 93 | #else | 92 | #else |
| 94 | static inline | 93 | static inline |
| 95 | struct tcp_md5sig_key *tcp_v4_md5_do_lookup(struct sock *sk, __be32 addr) | 94 | struct tcp_md5sig_key *tcp_v4_md5_do_lookup(struct sock *sk, __be32 addr) |
| @@ -583,11 +582,9 @@ static void tcp_v4_send_reset(struct sock *sk, struct sk_buff *skb) | |||
| 583 | arg.iov[0].iov_len += TCPOLEN_MD5SIG_ALIGNED; | 582 | arg.iov[0].iov_len += TCPOLEN_MD5SIG_ALIGNED; |
| 584 | rep.th.doff = arg.iov[0].iov_len / 4; | 583 | rep.th.doff = arg.iov[0].iov_len / 4; |
| 585 | 584 | ||
| 586 | tcp_v4_do_calc_md5_hash((__u8 *)&rep.opt[1], | 585 | tcp_v4_md5_hash_hdr((__u8 *) &rep.opt[1], |
| 587 | key, | 586 | key, ip_hdr(skb)->daddr, |
| 588 | ip_hdr(skb)->daddr, | 587 | ip_hdr(skb)->saddr, &rep.th); |
| 589 | ip_hdr(skb)->saddr, | ||
| 590 | &rep.th, arg.iov[0].iov_len); | ||
| 591 | } | 588 | } |
| 592 | #endif | 589 | #endif |
| 593 | arg.csum = csum_tcpudp_nofold(ip_hdr(skb)->daddr, | 590 | arg.csum = csum_tcpudp_nofold(ip_hdr(skb)->daddr, |
| @@ -657,11 +654,9 @@ static void tcp_v4_send_ack(struct sk_buff *skb, u32 seq, u32 ack, | |||
| 657 | arg.iov[0].iov_len += TCPOLEN_MD5SIG_ALIGNED; | 654 | arg.iov[0].iov_len += TCPOLEN_MD5SIG_ALIGNED; |
| 658 | rep.th.doff = arg.iov[0].iov_len/4; | 655 | rep.th.doff = arg.iov[0].iov_len/4; |
| 659 | 656 | ||
| 660 | tcp_v4_do_calc_md5_hash((__u8 *)&rep.opt[offset], | 657 | tcp_v4_md5_hash_hdr((__u8 *) &rep.opt[offset], |
| 661 | key, | 658 | key, ip_hdr(skb)->daddr, |
| 662 | ip_hdr(skb)->daddr, | 659 | ip_hdr(skb)->saddr, &rep.th); |
| 663 | ip_hdr(skb)->saddr, | ||
| 664 | &rep.th, arg.iov[0].iov_len); | ||
| 665 | } | 660 | } |
| 666 | #endif | 661 | #endif |
| 667 | arg.csum = csum_tcpudp_nofold(ip_hdr(skb)->daddr, | 662 | arg.csum = csum_tcpudp_nofold(ip_hdr(skb)->daddr, |
| @@ -989,28 +984,16 @@ static int tcp_v4_parse_md5_keys(struct sock *sk, char __user *optval, | |||
| 989 | newkey, cmd.tcpm_keylen); | 984 | newkey, cmd.tcpm_keylen); |
| 990 | } | 985 | } |
| 991 | 986 | ||
| 992 | static int tcp_v4_do_calc_md5_hash(char *md5_hash, struct tcp_md5sig_key *key, | 987 | static int tcp_v4_md5_hash_pseudoheader(struct tcp_md5sig_pool *hp, |
| 993 | __be32 saddr, __be32 daddr, | 988 | __be32 daddr, __be32 saddr, int nbytes) |
| 994 | struct tcphdr *th, | ||
| 995 | unsigned int tcplen) | ||
| 996 | { | 989 | { |
| 997 | struct tcp_md5sig_pool *hp; | ||
| 998 | struct tcp4_pseudohdr *bp; | 990 | struct tcp4_pseudohdr *bp; |
| 999 | int err; | 991 | struct scatterlist sg; |
| 1000 | |||
| 1001 | /* | ||
| 1002 | * Okay, so RFC2385 is turned on for this connection, | ||
| 1003 | * so we need to generate the MD5 hash for the packet now. | ||
| 1004 | */ | ||
| 1005 | |||
| 1006 | hp = tcp_get_md5sig_pool(); | ||
| 1007 | if (!hp) | ||
| 1008 | goto clear_hash_noput; | ||
| 1009 | 992 | ||
| 1010 | bp = &hp->md5_blk.ip4; | 993 | bp = &hp->md5_blk.ip4; |
| 1011 | 994 | ||
| 1012 | /* | 995 | /* |
| 1013 | * The TCP pseudo-header (in the order: source IP address, | 996 | * 1. the TCP pseudo-header (in the order: source IP address, |
| 1014 | * destination IP address, zero-padded protocol number, and | 997 | * destination IP address, zero-padded protocol number, and |
| 1015 | * segment length) | 998 | * segment length) |
| 1016 | */ | 999 | */ |
| @@ -1018,48 +1001,95 @@ static int tcp_v4_do_calc_md5_hash(char *md5_hash, struct tcp_md5sig_key *key, | |||
| 1018 | bp->daddr = daddr; | 1001 | bp->daddr = daddr; |
| 1019 | bp->pad = 0; | 1002 | bp->pad = 0; |
| 1020 | bp->protocol = IPPROTO_TCP; | 1003 | bp->protocol = IPPROTO_TCP; |
| 1021 | bp->len = htons(tcplen); | 1004 | bp->len = cpu_to_be16(nbytes); |
| 1022 | 1005 | ||
| 1023 | err = tcp_calc_md5_hash(md5_hash, key, sizeof(*bp), | 1006 | sg_init_one(&sg, bp, sizeof(*bp)); |
| 1024 | th, tcplen, hp); | 1007 | return crypto_hash_update(&hp->md5_desc, &sg, sizeof(*bp)); |
| 1025 | if (err) | 1008 | } |
| 1009 | |||
| 1010 | static int tcp_v4_md5_hash_hdr(char *md5_hash, struct tcp_md5sig_key *key, | ||
| 1011 | __be32 daddr, __be32 saddr, struct tcphdr *th) | ||
| 1012 | { | ||
| 1013 | struct tcp_md5sig_pool *hp; | ||
| 1014 | struct hash_desc *desc; | ||
| 1015 | |||
| 1016 | hp = tcp_get_md5sig_pool(); | ||
| 1017 | if (!hp) | ||
| 1018 | goto clear_hash_noput; | ||
| 1019 | desc = &hp->md5_desc; | ||
| 1020 | |||
| 1021 | if (crypto_hash_init(desc)) | ||
| 1022 | goto clear_hash; | ||
| 1023 | if (tcp_v4_md5_hash_pseudoheader(hp, daddr, saddr, th->doff << 2)) | ||
| 1024 | goto clear_hash; | ||
| 1025 | if (tcp_md5_hash_header(hp, th)) | ||
| 1026 | goto clear_hash; | ||
| 1027 | if (tcp_md5_hash_key(hp, key)) | ||
| 1028 | goto clear_hash; | ||
| 1029 | if (crypto_hash_final(desc, md5_hash)) | ||
| 1026 | goto clear_hash; | 1030 | goto clear_hash; |
| 1027 | 1031 | ||
| 1028 | /* Free up the crypto pool */ | ||
| 1029 | tcp_put_md5sig_pool(); | 1032 | tcp_put_md5sig_pool(); |
| 1030 | out: | ||
| 1031 | return 0; | 1033 | return 0; |
| 1034 | |||
| 1032 | clear_hash: | 1035 | clear_hash: |
| 1033 | tcp_put_md5sig_pool(); | 1036 | tcp_put_md5sig_pool(); |
| 1034 | clear_hash_noput: | 1037 | clear_hash_noput: |
| 1035 | memset(md5_hash, 0, 16); | 1038 | memset(md5_hash, 0, 16); |
| 1036 | goto out; | 1039 | return 1; |
| 1037 | } | 1040 | } |
| 1038 | 1041 | ||
| 1039 | int tcp_v4_calc_md5_hash(char *md5_hash, struct tcp_md5sig_key *key, | 1042 | int tcp_v4_md5_hash_skb(char *md5_hash, struct tcp_md5sig_key *key, |
| 1040 | struct sock *sk, | 1043 | struct sock *sk, struct request_sock *req, |
| 1041 | struct dst_entry *dst, | 1044 | struct sk_buff *skb) |
| 1042 | struct request_sock *req, | ||
| 1043 | struct tcphdr *th, | ||
| 1044 | unsigned int tcplen) | ||
| 1045 | { | 1045 | { |
| 1046 | struct tcp_md5sig_pool *hp; | ||
| 1047 | struct hash_desc *desc; | ||
| 1048 | struct tcphdr *th = tcp_hdr(skb); | ||
| 1046 | __be32 saddr, daddr; | 1049 | __be32 saddr, daddr; |
| 1047 | 1050 | ||
| 1048 | if (sk) { | 1051 | if (sk) { |
| 1049 | saddr = inet_sk(sk)->saddr; | 1052 | saddr = inet_sk(sk)->saddr; |
| 1050 | daddr = inet_sk(sk)->daddr; | 1053 | daddr = inet_sk(sk)->daddr; |
| 1054 | } else if (req) { | ||
| 1055 | saddr = inet_rsk(req)->loc_addr; | ||
| 1056 | daddr = inet_rsk(req)->rmt_addr; | ||
| 1051 | } else { | 1057 | } else { |
| 1052 | struct rtable *rt = (struct rtable *)dst; | 1058 | const struct iphdr *iph = ip_hdr(skb); |
| 1053 | BUG_ON(!rt); | 1059 | saddr = iph->saddr; |
| 1054 | saddr = rt->rt_src; | 1060 | daddr = iph->daddr; |
| 1055 | daddr = rt->rt_dst; | ||
| 1056 | } | 1061 | } |
| 1057 | return tcp_v4_do_calc_md5_hash(md5_hash, key, | 1062 | |
| 1058 | saddr, daddr, | 1063 | hp = tcp_get_md5sig_pool(); |
| 1059 | th, tcplen); | 1064 | if (!hp) |
| 1065 | goto clear_hash_noput; | ||
| 1066 | desc = &hp->md5_desc; | ||
| 1067 | |||
| 1068 | if (crypto_hash_init(desc)) | ||
| 1069 | goto clear_hash; | ||
| 1070 | |||
| 1071 | if (tcp_v4_md5_hash_pseudoheader(hp, daddr, saddr, skb->len)) | ||
| 1072 | goto clear_hash; | ||
| 1073 | if (tcp_md5_hash_header(hp, th)) | ||
| 1074 | goto clear_hash; | ||
| 1075 | if (tcp_md5_hash_skb_data(hp, skb, th->doff << 2)) | ||
| 1076 | goto clear_hash; | ||
| 1077 | if (tcp_md5_hash_key(hp, key)) | ||
| 1078 | goto clear_hash; | ||
| 1079 | if (crypto_hash_final(desc, md5_hash)) | ||
| 1080 | goto clear_hash; | ||
| 1081 | |||
| 1082 | tcp_put_md5sig_pool(); | ||
| 1083 | return 0; | ||
| 1084 | |||
| 1085 | clear_hash: | ||
| 1086 | tcp_put_md5sig_pool(); | ||
| 1087 | clear_hash_noput: | ||
| 1088 | memset(md5_hash, 0, 16); | ||
| 1089 | return 1; | ||
| 1060 | } | 1090 | } |
| 1061 | 1091 | ||
| 1062 | EXPORT_SYMBOL(tcp_v4_calc_md5_hash); | 1092 | EXPORT_SYMBOL(tcp_v4_md5_hash_skb); |
| 1063 | 1093 | ||
| 1064 | static int tcp_v4_inbound_md5_hash(struct sock *sk, struct sk_buff *skb) | 1094 | static int tcp_v4_inbound_md5_hash(struct sock *sk, struct sk_buff *skb) |
| 1065 | { | 1095 | { |
| @@ -1104,10 +1134,9 @@ static int tcp_v4_inbound_md5_hash(struct sock *sk, struct sk_buff *skb) | |||
| 1104 | /* Okay, so this is hash_expected and hash_location - | 1134 | /* Okay, so this is hash_expected and hash_location - |
| 1105 | * so we need to calculate the checksum. | 1135 | * so we need to calculate the checksum. |
| 1106 | */ | 1136 | */ |
| 1107 | genhash = tcp_v4_do_calc_md5_hash(newhash, | 1137 | genhash = tcp_v4_md5_hash_skb(newhash, |
| 1108 | hash_expected, | 1138 | hash_expected, |
| 1109 | iph->saddr, iph->daddr, | 1139 | NULL, NULL, skb); |
| 1110 | th, skb->len); | ||
| 1111 | 1140 | ||
| 1112 | if (genhash || memcmp(hash_location, newhash, 16) != 0) { | 1141 | if (genhash || memcmp(hash_location, newhash, 16) != 0) { |
| 1113 | if (net_ratelimit()) { | 1142 | if (net_ratelimit()) { |
| @@ -1356,6 +1385,7 @@ struct sock *tcp_v4_syn_recv_sock(struct sock *sk, struct sk_buff *skb, | |||
| 1356 | if (newkey != NULL) | 1385 | if (newkey != NULL) |
| 1357 | tcp_v4_md5_do_add(newsk, inet_sk(sk)->daddr, | 1386 | tcp_v4_md5_do_add(newsk, inet_sk(sk)->daddr, |
| 1358 | newkey, key->keylen); | 1387 | newkey, key->keylen); |
| 1388 | newsk->sk_route_caps &= ~NETIF_F_GSO_MASK; | ||
| 1359 | } | 1389 | } |
| 1360 | #endif | 1390 | #endif |
| 1361 | 1391 | ||
| @@ -1719,7 +1749,7 @@ struct inet_connection_sock_af_ops ipv4_specific = { | |||
| 1719 | #ifdef CONFIG_TCP_MD5SIG | 1749 | #ifdef CONFIG_TCP_MD5SIG |
| 1720 | static struct tcp_sock_af_ops tcp_sock_ipv4_specific = { | 1750 | static struct tcp_sock_af_ops tcp_sock_ipv4_specific = { |
| 1721 | .md5_lookup = tcp_v4_md5_lookup, | 1751 | .md5_lookup = tcp_v4_md5_lookup, |
| 1722 | .calc_md5_hash = tcp_v4_calc_md5_hash, | 1752 | .calc_md5_hash = tcp_v4_md5_hash_skb, |
| 1723 | .md5_add = tcp_v4_md5_add_func, | 1753 | .md5_add = tcp_v4_md5_add_func, |
| 1724 | .md5_parse = tcp_v4_parse_md5_keys, | 1754 | .md5_parse = tcp_v4_parse_md5_keys, |
| 1725 | }; | 1755 | }; |
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 36a19707f67f..958ff486165f 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c | |||
| @@ -540,8 +540,10 @@ static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it, | |||
| 540 | * room for it. | 540 | * room for it. |
| 541 | */ | 541 | */ |
| 542 | md5 = tp->af_specific->md5_lookup(sk, sk); | 542 | md5 = tp->af_specific->md5_lookup(sk, sk); |
| 543 | if (md5) | 543 | if (md5) { |
| 544 | tcp_header_size += TCPOLEN_MD5SIG_ALIGNED; | 544 | tcp_header_size += TCPOLEN_MD5SIG_ALIGNED; |
| 545 | sk->sk_route_caps &= ~NETIF_F_GSO_MASK; | ||
| 546 | } | ||
| 545 | #endif | 547 | #endif |
| 546 | 548 | ||
| 547 | skb_push(skb, tcp_header_size); | 549 | skb_push(skb, tcp_header_size); |
| @@ -602,10 +604,7 @@ static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it, | |||
| 602 | /* Calculate the MD5 hash, as we have all we need now */ | 604 | /* Calculate the MD5 hash, as we have all we need now */ |
| 603 | if (md5) { | 605 | if (md5) { |
| 604 | tp->af_specific->calc_md5_hash(md5_hash_location, | 606 | tp->af_specific->calc_md5_hash(md5_hash_location, |
| 605 | md5, | 607 | md5, sk, NULL, skb); |
| 606 | sk, NULL, NULL, | ||
| 607 | tcp_hdr(skb), | ||
| 608 | skb->len); | ||
| 609 | } | 608 | } |
| 610 | #endif | 609 | #endif |
| 611 | 610 | ||
| @@ -2264,10 +2263,7 @@ struct sk_buff *tcp_make_synack(struct sock *sk, struct dst_entry *dst, | |||
| 2264 | /* Okay, we have all we need - do the md5 hash if needed */ | 2263 | /* Okay, we have all we need - do the md5 hash if needed */ |
| 2265 | if (md5) { | 2264 | if (md5) { |
| 2266 | tp->af_specific->calc_md5_hash(md5_hash_location, | 2265 | tp->af_specific->calc_md5_hash(md5_hash_location, |
| 2267 | md5, | 2266 | md5, NULL, req, skb); |
| 2268 | NULL, dst, req, | ||
| 2269 | tcp_hdr(skb), | ||
| 2270 | skb->len); | ||
| 2271 | } | 2267 | } |
| 2272 | #endif | 2268 | #endif |
| 2273 | 2269 | ||
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index ca5b93a5c02a..ae45f9835014 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c | |||
| @@ -736,64 +736,105 @@ static int tcp_v6_parse_md5_keys (struct sock *sk, char __user *optval, | |||
| 736 | return tcp_v6_md5_do_add(sk, &sin6->sin6_addr, newkey, cmd.tcpm_keylen); | 736 | return tcp_v6_md5_do_add(sk, &sin6->sin6_addr, newkey, cmd.tcpm_keylen); |
| 737 | } | 737 | } |
| 738 | 738 | ||
| 739 | static int tcp_v6_do_calc_md5_hash(char *md5_hash, struct tcp_md5sig_key *key, | 739 | static int tcp_v6_md5_hash_pseudoheader(struct tcp_md5sig_pool *hp, |
| 740 | struct in6_addr *saddr, | 740 | struct in6_addr *daddr, |
| 741 | struct in6_addr *daddr, | 741 | struct in6_addr *saddr, int nbytes) |
| 742 | struct tcphdr *th, unsigned int tcplen) | ||
| 743 | { | 742 | { |
| 744 | struct tcp_md5sig_pool *hp; | ||
| 745 | struct tcp6_pseudohdr *bp; | 743 | struct tcp6_pseudohdr *bp; |
| 746 | int err; | 744 | struct scatterlist sg; |
| 747 | |||
| 748 | hp = tcp_get_md5sig_pool(); | ||
| 749 | if (!hp) { | ||
| 750 | printk(KERN_WARNING "%s(): hash pool not found...\n", __func__); | ||
| 751 | goto clear_hash_noput; | ||
| 752 | } | ||
| 753 | 745 | ||
| 754 | bp = &hp->md5_blk.ip6; | 746 | bp = &hp->md5_blk.ip6; |
| 755 | |||
| 756 | /* 1. TCP pseudo-header (RFC2460) */ | 747 | /* 1. TCP pseudo-header (RFC2460) */ |
| 757 | ipv6_addr_copy(&bp->saddr, saddr); | 748 | ipv6_addr_copy(&bp->saddr, saddr); |
| 758 | ipv6_addr_copy(&bp->daddr, daddr); | 749 | ipv6_addr_copy(&bp->daddr, daddr); |
| 759 | bp->len = htonl(tcplen); | 750 | bp->protocol = cpu_to_be32(IPPROTO_TCP); |
| 760 | bp->protocol = htonl(IPPROTO_TCP); | 751 | bp->len = cpu_to_be16(nbytes); |
| 761 | 752 | ||
| 762 | err = tcp_calc_md5_hash(md5_hash, key, sizeof(*bp), | 753 | sg_init_one(&sg, bp, sizeof(*bp)); |
| 763 | th, tcplen, hp); | 754 | return crypto_hash_update(&hp->md5_desc, &sg, sizeof(*bp)); |
| 755 | } | ||
| 764 | 756 | ||
| 765 | if (err) | 757 | static int tcp_v6_md5_hash_hdr(char *md5_hash, struct tcp_md5sig_key *key, |
| 758 | struct in6_addr *daddr, struct in6_addr *saddr, | ||
| 759 | struct tcphdr *th) | ||
| 760 | { | ||
| 761 | struct tcp_md5sig_pool *hp; | ||
| 762 | struct hash_desc *desc; | ||
| 763 | |||
| 764 | hp = tcp_get_md5sig_pool(); | ||
| 765 | if (!hp) | ||
| 766 | goto clear_hash_noput; | ||
| 767 | desc = &hp->md5_desc; | ||
| 768 | |||
| 769 | if (crypto_hash_init(desc)) | ||
| 770 | goto clear_hash; | ||
| 771 | if (tcp_v6_md5_hash_pseudoheader(hp, daddr, saddr, th->doff << 2)) | ||
| 772 | goto clear_hash; | ||
| 773 | if (tcp_md5_hash_header(hp, th)) | ||
| 774 | goto clear_hash; | ||
| 775 | if (tcp_md5_hash_key(hp, key)) | ||
| 776 | goto clear_hash; | ||
| 777 | if (crypto_hash_final(desc, md5_hash)) | ||
| 766 | goto clear_hash; | 778 | goto clear_hash; |
| 767 | 779 | ||
| 768 | /* Free up the crypto pool */ | ||
| 769 | tcp_put_md5sig_pool(); | 780 | tcp_put_md5sig_pool(); |
| 770 | out: | ||
| 771 | return 0; | 781 | return 0; |
| 782 | |||
| 772 | clear_hash: | 783 | clear_hash: |
| 773 | tcp_put_md5sig_pool(); | 784 | tcp_put_md5sig_pool(); |
| 774 | clear_hash_noput: | 785 | clear_hash_noput: |
| 775 | memset(md5_hash, 0, 16); | 786 | memset(md5_hash, 0, 16); |
| 776 | goto out; | 787 | return 1; |
| 777 | } | 788 | } |
| 778 | 789 | ||
| 779 | static int tcp_v6_calc_md5_hash(char *md5_hash, struct tcp_md5sig_key *key, | 790 | static int tcp_v6_md5_hash_skb(char *md5_hash, struct tcp_md5sig_key *key, |
| 780 | struct sock *sk, | 791 | struct sock *sk, struct request_sock *req, |
| 781 | struct dst_entry *dst, | 792 | struct sk_buff *skb) |
| 782 | struct request_sock *req, | ||
| 783 | struct tcphdr *th, unsigned int tcplen) | ||
| 784 | { | 793 | { |
| 785 | struct in6_addr *saddr, *daddr; | 794 | struct in6_addr *saddr, *daddr; |
| 795 | struct tcp_md5sig_pool *hp; | ||
| 796 | struct hash_desc *desc; | ||
| 797 | struct tcphdr *th = tcp_hdr(skb); | ||
| 786 | 798 | ||
| 787 | if (sk) { | 799 | if (sk) { |
| 788 | saddr = &inet6_sk(sk)->saddr; | 800 | saddr = &inet6_sk(sk)->saddr; |
| 789 | daddr = &inet6_sk(sk)->daddr; | 801 | daddr = &inet6_sk(sk)->daddr; |
| 790 | } else { | 802 | } else if (req) { |
| 791 | saddr = &inet6_rsk(req)->loc_addr; | 803 | saddr = &inet6_rsk(req)->loc_addr; |
| 792 | daddr = &inet6_rsk(req)->rmt_addr; | 804 | daddr = &inet6_rsk(req)->rmt_addr; |
| 805 | } else { | ||
| 806 | struct ipv6hdr *ip6h = ipv6_hdr(skb); | ||
| 807 | saddr = &ip6h->saddr; | ||
| 808 | daddr = &ip6h->daddr; | ||
| 793 | } | 809 | } |
| 794 | return tcp_v6_do_calc_md5_hash(md5_hash, key, | 810 | |
| 795 | saddr, daddr, | 811 | hp = tcp_get_md5sig_pool(); |
| 796 | th, tcplen); | 812 | if (!hp) |
| 813 | goto clear_hash_noput; | ||
| 814 | desc = &hp->md5_desc; | ||
| 815 | |||
| 816 | if (crypto_hash_init(desc)) | ||
| 817 | goto clear_hash; | ||
| 818 | |||
| 819 | if (tcp_v6_md5_hash_pseudoheader(hp, daddr, saddr, skb->len)) | ||
| 820 | goto clear_hash; | ||
| 821 | if (tcp_md5_hash_header(hp, th)) | ||
| 822 | goto clear_hash; | ||
| 823 | if (tcp_md5_hash_skb_data(hp, skb, th->doff << 2)) | ||
| 824 | goto clear_hash; | ||
| 825 | if (tcp_md5_hash_key(hp, key)) | ||
| 826 | goto clear_hash; | ||
| 827 | if (crypto_hash_final(desc, md5_hash)) | ||
| 828 | goto clear_hash; | ||
| 829 | |||
| 830 | tcp_put_md5sig_pool(); | ||
| 831 | return 0; | ||
| 832 | |||
| 833 | clear_hash: | ||
| 834 | tcp_put_md5sig_pool(); | ||
| 835 | clear_hash_noput: | ||
| 836 | memset(md5_hash, 0, 16); | ||
| 837 | return 1; | ||
| 797 | } | 838 | } |
| 798 | 839 | ||
| 799 | static int tcp_v6_inbound_md5_hash (struct sock *sk, struct sk_buff *skb) | 840 | static int tcp_v6_inbound_md5_hash (struct sock *sk, struct sk_buff *skb) |
| @@ -834,10 +875,10 @@ static int tcp_v6_inbound_md5_hash (struct sock *sk, struct sk_buff *skb) | |||
| 834 | } | 875 | } |
| 835 | 876 | ||
| 836 | /* check the signature */ | 877 | /* check the signature */ |
| 837 | genhash = tcp_v6_do_calc_md5_hash(newhash, | 878 | genhash = tcp_v6_md5_hash_skb(newhash, |
| 838 | hash_expected, | 879 | hash_expected, |
| 839 | &ip6h->saddr, &ip6h->daddr, | 880 | NULL, NULL, skb); |
| 840 | th, skb->len); | 881 | |
| 841 | if (genhash || memcmp(hash_location, newhash, 16) != 0) { | 882 | if (genhash || memcmp(hash_location, newhash, 16) != 0) { |
| 842 | if (net_ratelimit()) { | 883 | if (net_ratelimit()) { |
| 843 | printk(KERN_INFO "MD5 Hash %s for " | 884 | printk(KERN_INFO "MD5 Hash %s for " |
| @@ -974,10 +1015,9 @@ static void tcp_v6_send_reset(struct sock *sk, struct sk_buff *skb) | |||
| 974 | (TCPOPT_NOP << 16) | | 1015 | (TCPOPT_NOP << 16) | |
| 975 | (TCPOPT_MD5SIG << 8) | | 1016 | (TCPOPT_MD5SIG << 8) | |
| 976 | TCPOLEN_MD5SIG); | 1017 | TCPOLEN_MD5SIG); |
| 977 | tcp_v6_do_calc_md5_hash((__u8 *)&opt[1], key, | 1018 | tcp_v6_md5_hash_hdr((__u8 *)&opt[1], key, |
| 978 | &ipv6_hdr(skb)->daddr, | 1019 | &ipv6_hdr(skb)->daddr, |
| 979 | &ipv6_hdr(skb)->saddr, | 1020 | &ipv6_hdr(skb)->saddr, t1); |
| 980 | t1, tot_len); | ||
| 981 | } | 1021 | } |
| 982 | #endif | 1022 | #endif |
| 983 | 1023 | ||
| @@ -1064,10 +1104,9 @@ static void tcp_v6_send_ack(struct sk_buff *skb, u32 seq, u32 ack, u32 win, u32 | |||
| 1064 | if (key) { | 1104 | if (key) { |
| 1065 | *topt++ = htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) | | 1105 | *topt++ = htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) | |
| 1066 | (TCPOPT_MD5SIG << 8) | TCPOLEN_MD5SIG); | 1106 | (TCPOPT_MD5SIG << 8) | TCPOLEN_MD5SIG); |
| 1067 | tcp_v6_do_calc_md5_hash((__u8 *)topt, key, | 1107 | tcp_v6_md5_hash_hdr((__u8 *)topt, key, |
| 1068 | &ipv6_hdr(skb)->daddr, | 1108 | &ipv6_hdr(skb)->daddr, |
| 1069 | &ipv6_hdr(skb)->saddr, | 1109 | &ipv6_hdr(skb)->saddr, t1); |
| 1070 | t1, tot_len); | ||
| 1071 | } | 1110 | } |
| 1072 | #endif | 1111 | #endif |
| 1073 | 1112 | ||
| @@ -1783,7 +1822,7 @@ static struct inet_connection_sock_af_ops ipv6_specific = { | |||
| 1783 | #ifdef CONFIG_TCP_MD5SIG | 1822 | #ifdef CONFIG_TCP_MD5SIG |
| 1784 | static struct tcp_sock_af_ops tcp_sock_ipv6_specific = { | 1823 | static struct tcp_sock_af_ops tcp_sock_ipv6_specific = { |
| 1785 | .md5_lookup = tcp_v6_md5_lookup, | 1824 | .md5_lookup = tcp_v6_md5_lookup, |
| 1786 | .calc_md5_hash = tcp_v6_calc_md5_hash, | 1825 | .calc_md5_hash = tcp_v6_md5_hash_skb, |
| 1787 | .md5_add = tcp_v6_md5_add_func, | 1826 | .md5_add = tcp_v6_md5_add_func, |
| 1788 | .md5_parse = tcp_v6_parse_md5_keys, | 1827 | .md5_parse = tcp_v6_parse_md5_keys, |
| 1789 | }; | 1828 | }; |
| @@ -1815,7 +1854,7 @@ static struct inet_connection_sock_af_ops ipv6_mapped = { | |||
| 1815 | #ifdef CONFIG_TCP_MD5SIG | 1854 | #ifdef CONFIG_TCP_MD5SIG |
| 1816 | static struct tcp_sock_af_ops tcp_sock_ipv6_mapped_specific = { | 1855 | static struct tcp_sock_af_ops tcp_sock_ipv6_mapped_specific = { |
| 1817 | .md5_lookup = tcp_v4_md5_lookup, | 1856 | .md5_lookup = tcp_v4_md5_lookup, |
| 1818 | .calc_md5_hash = tcp_v4_calc_md5_hash, | 1857 | .calc_md5_hash = tcp_v4_md5_hash_skb, |
| 1819 | .md5_add = tcp_v6_md5_add_func, | 1858 | .md5_add = tcp_v6_md5_add_func, |
| 1820 | .md5_parse = tcp_v6_parse_md5_keys, | 1859 | .md5_parse = tcp_v6_parse_md5_keys, |
| 1821 | }; | 1860 | }; |
