diff options
Diffstat (limited to 'net/ipv6/tcp_ipv6.c')
-rw-r--r-- | net/ipv6/tcp_ipv6.c | 45 |
1 files changed, 35 insertions, 10 deletions
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index b47cce8fea44..caf0cc1c00e1 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c | |||
@@ -69,9 +69,6 @@ | |||
69 | #include <linux/crypto.h> | 69 | #include <linux/crypto.h> |
70 | #include <linux/scatterlist.h> | 70 | #include <linux/scatterlist.h> |
71 | 71 | ||
72 | /* Socket used for sending RSTs and ACKs */ | ||
73 | static struct socket *tcp6_socket; | ||
74 | |||
75 | static void tcp_v6_send_reset(struct sock *sk, struct sk_buff *skb); | 72 | static void tcp_v6_send_reset(struct sock *sk, struct sk_buff *skb); |
76 | static void tcp_v6_reqsk_send_ack(struct sk_buff *skb, struct request_sock *req); | 73 | static void tcp_v6_reqsk_send_ack(struct sk_buff *skb, struct request_sock *req); |
77 | static void tcp_v6_send_check(struct sock *sk, int len, | 74 | static void tcp_v6_send_check(struct sock *sk, int len, |
@@ -991,6 +988,8 @@ static void tcp_v6_send_reset(struct sock *sk, struct sk_buff *skb) | |||
991 | struct tcphdr *th = tcp_hdr(skb), *t1; | 988 | struct tcphdr *th = tcp_hdr(skb), *t1; |
992 | struct sk_buff *buff; | 989 | struct sk_buff *buff; |
993 | struct flowi fl; | 990 | struct flowi fl; |
991 | struct net *net = skb->dst->dev->nd_net; | ||
992 | struct sock *ctl_sk = net->ipv6.tcp_sk; | ||
994 | unsigned int tot_len = sizeof(*th); | 993 | unsigned int tot_len = sizeof(*th); |
995 | #ifdef CONFIG_TCP_MD5SIG | 994 | #ifdef CONFIG_TCP_MD5SIG |
996 | struct tcp_md5sig_key *key; | 995 | struct tcp_md5sig_key *key; |
@@ -1075,10 +1074,10 @@ static void tcp_v6_send_reset(struct sock *sk, struct sk_buff *skb) | |||
1075 | * Underlying function will use this to retrieve the network | 1074 | * Underlying function will use this to retrieve the network |
1076 | * namespace | 1075 | * namespace |
1077 | */ | 1076 | */ |
1078 | if (!ip6_dst_lookup(tcp6_socket->sk, &buff->dst, &fl)) { | 1077 | if (!ip6_dst_lookup(ctl_sk, &buff->dst, &fl)) { |
1079 | 1078 | ||
1080 | if (xfrm_lookup(&buff->dst, &fl, NULL, 0) >= 0) { | 1079 | if (xfrm_lookup(&buff->dst, &fl, NULL, 0) >= 0) { |
1081 | ip6_xmit(tcp6_socket->sk, buff, &fl, NULL, 0); | 1080 | ip6_xmit(ctl_sk, buff, &fl, NULL, 0); |
1082 | TCP_INC_STATS_BH(TCP_MIB_OUTSEGS); | 1081 | TCP_INC_STATS_BH(TCP_MIB_OUTSEGS); |
1083 | TCP_INC_STATS_BH(TCP_MIB_OUTRSTS); | 1082 | TCP_INC_STATS_BH(TCP_MIB_OUTRSTS); |
1084 | return; | 1083 | return; |
@@ -1094,6 +1093,8 @@ static void tcp_v6_send_ack(struct tcp_timewait_sock *tw, | |||
1094 | struct tcphdr *th = tcp_hdr(skb), *t1; | 1093 | struct tcphdr *th = tcp_hdr(skb), *t1; |
1095 | struct sk_buff *buff; | 1094 | struct sk_buff *buff; |
1096 | struct flowi fl; | 1095 | struct flowi fl; |
1096 | struct net *net = skb->dev->nd_net; | ||
1097 | struct sock *ctl_sk = net->ipv6.tcp_sk; | ||
1097 | unsigned int tot_len = sizeof(struct tcphdr); | 1098 | unsigned int tot_len = sizeof(struct tcphdr); |
1098 | __be32 *topt; | 1099 | __be32 *topt; |
1099 | #ifdef CONFIG_TCP_MD5SIG | 1100 | #ifdef CONFIG_TCP_MD5SIG |
@@ -1175,9 +1176,9 @@ static void tcp_v6_send_ack(struct tcp_timewait_sock *tw, | |||
1175 | fl.fl_ip_sport = t1->source; | 1176 | fl.fl_ip_sport = t1->source; |
1176 | security_skb_classify_flow(skb, &fl); | 1177 | security_skb_classify_flow(skb, &fl); |
1177 | 1178 | ||
1178 | if (!ip6_dst_lookup(tcp6_socket->sk, &buff->dst, &fl)) { | 1179 | if (!ip6_dst_lookup(ctl_sk, &buff->dst, &fl)) { |
1179 | if (xfrm_lookup(&buff->dst, &fl, NULL, 0) >= 0) { | 1180 | if (xfrm_lookup(&buff->dst, &fl, NULL, 0) >= 0) { |
1180 | ip6_xmit(tcp6_socket->sk, buff, &fl, NULL, 0); | 1181 | ip6_xmit(ctl_sk, buff, &fl, NULL, 0); |
1181 | TCP_INC_STATS_BH(TCP_MIB_OUTSEGS); | 1182 | TCP_INC_STATS_BH(TCP_MIB_OUTSEGS); |
1182 | return; | 1183 | return; |
1183 | } | 1184 | } |
@@ -2198,6 +2199,31 @@ static struct inet_protosw tcpv6_protosw = { | |||
2198 | INET_PROTOSW_ICSK, | 2199 | INET_PROTOSW_ICSK, |
2199 | }; | 2200 | }; |
2200 | 2201 | ||
2202 | static int tcpv6_net_init(struct net *net) | ||
2203 | { | ||
2204 | int err; | ||
2205 | struct socket *sock; | ||
2206 | struct sock *sk; | ||
2207 | |||
2208 | err = inet_csk_ctl_sock_create(&sock, PF_INET6, SOCK_RAW, IPPROTO_TCP); | ||
2209 | if (err) | ||
2210 | return err; | ||
2211 | |||
2212 | net->ipv6.tcp_sk = sk = sock->sk; | ||
2213 | sk_change_net(sk, net); | ||
2214 | return err; | ||
2215 | } | ||
2216 | |||
2217 | static void tcpv6_net_exit(struct net *net) | ||
2218 | { | ||
2219 | sk_release_kernel(net->ipv6.tcp_sk); | ||
2220 | } | ||
2221 | |||
2222 | static struct pernet_operations tcpv6_net_ops = { | ||
2223 | .init = tcpv6_net_init, | ||
2224 | .exit = tcpv6_net_exit, | ||
2225 | }; | ||
2226 | |||
2201 | int __init tcpv6_init(void) | 2227 | int __init tcpv6_init(void) |
2202 | { | 2228 | { |
2203 | int ret; | 2229 | int ret; |
@@ -2211,8 +2237,7 @@ int __init tcpv6_init(void) | |||
2211 | if (ret) | 2237 | if (ret) |
2212 | goto out_tcpv6_protocol; | 2238 | goto out_tcpv6_protocol; |
2213 | 2239 | ||
2214 | ret = inet_csk_ctl_sock_create(&tcp6_socket, PF_INET6, | 2240 | ret = register_pernet_subsys(&tcpv6_net_ops); |
2215 | SOCK_RAW, IPPROTO_TCP); | ||
2216 | if (ret) | 2241 | if (ret) |
2217 | goto out_tcpv6_protosw; | 2242 | goto out_tcpv6_protosw; |
2218 | out: | 2243 | out: |
@@ -2227,7 +2252,7 @@ out_tcpv6_protosw: | |||
2227 | 2252 | ||
2228 | void tcpv6_exit(void) | 2253 | void tcpv6_exit(void) |
2229 | { | 2254 | { |
2230 | sock_release(tcp6_socket); | 2255 | unregister_pernet_subsys(&tcpv6_net_ops); |
2231 | inet6_unregister_protosw(&tcpv6_protosw); | 2256 | inet6_unregister_protosw(&tcpv6_protosw); |
2232 | inet6_del_protocol(&tcpv6_protocol, IPPROTO_TCP); | 2257 | inet6_del_protocol(&tcpv6_protocol, IPPROTO_TCP); |
2233 | } | 2258 | } |