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 | }; |