aboutsummaryrefslogtreecommitdiffstats
path: root/net/dccp/ipv6.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/dccp/ipv6.c')
-rw-r--r--net/dccp/ipv6.c93
1 files changed, 55 insertions, 38 deletions
diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c
index 490333d47c7b..9b1129bb7ece 100644
--- a/net/dccp/ipv6.c
+++ b/net/dccp/ipv6.c
@@ -33,8 +33,7 @@
33#include "ipv6.h" 33#include "ipv6.h"
34#include "feat.h" 34#include "feat.h"
35 35
36/* Socket used for sending RSTs and ACKs */ 36/* The per-net dccp.v6_ctl_sk is used for sending RSTs and ACKs */
37static struct socket *dccp_v6_ctl_socket;
38 37
39static struct inet_connection_sock_af_ops dccp_ipv6_mapped; 38static struct inet_connection_sock_af_ops dccp_ipv6_mapped;
40static struct inet_connection_sock_af_ops dccp_ipv6_af_ops; 39static struct inet_connection_sock_af_ops dccp_ipv6_af_ops;
@@ -95,7 +94,8 @@ static void dccp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
95 int err; 94 int err;
96 __u64 seq; 95 __u64 seq;
97 96
98 sk = inet6_lookup(&init_net, &dccp_hashinfo, &hdr->daddr, dh->dccph_dport, 97 sk = inet6_lookup(dev_net(skb->dev), &dccp_hashinfo,
98 &hdr->daddr, dh->dccph_dport,
99 &hdr->saddr, dh->dccph_sport, inet6_iif(skb)); 99 &hdr->saddr, dh->dccph_sport, inet6_iif(skb));
100 100
101 if (sk == NULL) { 101 if (sk == NULL) {
@@ -224,8 +224,7 @@ out:
224} 224}
225 225
226 226
227static int dccp_v6_send_response(struct sock *sk, struct request_sock *req, 227static int dccp_v6_send_response(struct sock *sk, struct request_sock *req)
228 struct dst_entry *dst)
229{ 228{
230 struct inet6_request_sock *ireq6 = inet6_rsk(req); 229 struct inet6_request_sock *ireq6 = inet6_rsk(req);
231 struct ipv6_pinfo *np = inet6_sk(sk); 230 struct ipv6_pinfo *np = inet6_sk(sk);
@@ -234,6 +233,7 @@ static int dccp_v6_send_response(struct sock *sk, struct request_sock *req,
234 struct in6_addr *final_p = NULL, final; 233 struct in6_addr *final_p = NULL, final;
235 struct flowi fl; 234 struct flowi fl;
236 int err = -1; 235 int err = -1;
236 struct dst_entry *dst;
237 237
238 memset(&fl, 0, sizeof(fl)); 238 memset(&fl, 0, sizeof(fl));
239 fl.proto = IPPROTO_DCCP; 239 fl.proto = IPPROTO_DCCP;
@@ -245,28 +245,26 @@ static int dccp_v6_send_response(struct sock *sk, struct request_sock *req,
245 fl.fl_ip_sport = inet_sk(sk)->sport; 245 fl.fl_ip_sport = inet_sk(sk)->sport;
246 security_req_classify_flow(req, &fl); 246 security_req_classify_flow(req, &fl);
247 247
248 if (dst == NULL) { 248 opt = np->opt;
249 opt = np->opt;
250 249
251 if (opt != NULL && opt->srcrt != NULL) { 250 if (opt != NULL && opt->srcrt != NULL) {
252 const struct rt0_hdr *rt0 = (struct rt0_hdr *)opt->srcrt; 251 const struct rt0_hdr *rt0 = (struct rt0_hdr *)opt->srcrt;
253 252
254 ipv6_addr_copy(&final, &fl.fl6_dst); 253 ipv6_addr_copy(&final, &fl.fl6_dst);
255 ipv6_addr_copy(&fl.fl6_dst, rt0->addr); 254 ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
256 final_p = &final; 255 final_p = &final;
257 } 256 }
258 257
259 err = ip6_dst_lookup(sk, &dst, &fl); 258 err = ip6_dst_lookup(sk, &dst, &fl);
260 if (err) 259 if (err)
261 goto done; 260 goto done;
262 261
263 if (final_p) 262 if (final_p)
264 ipv6_addr_copy(&fl.fl6_dst, final_p); 263 ipv6_addr_copy(&fl.fl6_dst, final_p);
265 264
266 err = xfrm_lookup(&dst, &fl, sk, 0); 265 err = xfrm_lookup(&dst, &fl, sk, 0);
267 if (err < 0) 266 if (err < 0)
268 goto done; 267 goto done;
269 }
270 268
271 skb = dccp_make_response(sk, dst, req); 269 skb = dccp_make_response(sk, dst, req);
272 if (skb != NULL) { 270 if (skb != NULL) {
@@ -298,6 +296,8 @@ static void dccp_v6_ctl_send_reset(struct sock *sk, struct sk_buff *rxskb)
298 struct ipv6hdr *rxip6h; 296 struct ipv6hdr *rxip6h;
299 struct sk_buff *skb; 297 struct sk_buff *skb;
300 struct flowi fl; 298 struct flowi fl;
299 struct net *net = dev_net(rxskb->dst->dev);
300 struct sock *ctl_sk = net->dccp.v6_ctl_sk;
301 301
302 if (dccp_hdr(rxskb)->dccph_type == DCCP_PKT_RESET) 302 if (dccp_hdr(rxskb)->dccph_type == DCCP_PKT_RESET)
303 return; 303 return;
@@ -305,7 +305,7 @@ static void dccp_v6_ctl_send_reset(struct sock *sk, struct sk_buff *rxskb)
305 if (!ipv6_unicast_destination(rxskb)) 305 if (!ipv6_unicast_destination(rxskb))
306 return; 306 return;
307 307
308 skb = dccp_ctl_make_reset(dccp_v6_ctl_socket, rxskb); 308 skb = dccp_ctl_make_reset(ctl_sk, rxskb);
309 if (skb == NULL) 309 if (skb == NULL)
310 return; 310 return;
311 311
@@ -324,9 +324,9 @@ static void dccp_v6_ctl_send_reset(struct sock *sk, struct sk_buff *rxskb)
324 security_skb_classify_flow(rxskb, &fl); 324 security_skb_classify_flow(rxskb, &fl);
325 325
326 /* sk = NULL, but it is safe for now. RST socket required. */ 326 /* sk = NULL, but it is safe for now. RST socket required. */
327 if (!ip6_dst_lookup(NULL, &skb->dst, &fl)) { 327 if (!ip6_dst_lookup(ctl_sk, &skb->dst, &fl)) {
328 if (xfrm_lookup(&skb->dst, &fl, NULL, 0) >= 0) { 328 if (xfrm_lookup(&skb->dst, &fl, NULL, 0) >= 0) {
329 ip6_xmit(dccp_v6_ctl_socket->sk, skb, &fl, NULL, 0); 329 ip6_xmit(ctl_sk, skb, &fl, NULL, 0);
330 DCCP_INC_STATS_BH(DCCP_MIB_OUTSEGS); 330 DCCP_INC_STATS_BH(DCCP_MIB_OUTSEGS);
331 DCCP_INC_STATS_BH(DCCP_MIB_OUTRSTS); 331 DCCP_INC_STATS_BH(DCCP_MIB_OUTRSTS);
332 return; 332 return;
@@ -360,7 +360,7 @@ static struct sock *dccp_v6_hnd_req(struct sock *sk,struct sk_buff *skb)
360 if (req != NULL) 360 if (req != NULL)
361 return dccp_check_req(sk, skb, req, prev); 361 return dccp_check_req(sk, skb, req, prev);
362 362
363 nsk = __inet6_lookup_established(&init_net, &dccp_hashinfo, 363 nsk = __inet6_lookup_established(sock_net(sk), &dccp_hashinfo,
364 &iph->saddr, dh->dccph_sport, 364 &iph->saddr, dh->dccph_sport,
365 &iph->daddr, ntohs(dh->dccph_dport), 365 &iph->daddr, ntohs(dh->dccph_dport),
366 inet6_iif(skb)); 366 inet6_iif(skb));
@@ -448,7 +448,7 @@ static int dccp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
448 dreq->dreq_iss = dccp_v6_init_sequence(skb); 448 dreq->dreq_iss = dccp_v6_init_sequence(skb);
449 dreq->dreq_service = service; 449 dreq->dreq_service = service;
450 450
451 if (dccp_v6_send_response(sk, req, NULL)) 451 if (dccp_v6_send_response(sk, req))
452 goto drop_and_free; 452 goto drop_and_free;
453 453
454 inet6_csk_reqsk_queue_hash_add(sk, req, DCCP_TIMEOUT_INIT); 454 inet6_csk_reqsk_queue_hash_add(sk, req, DCCP_TIMEOUT_INIT);
@@ -625,7 +625,7 @@ static struct sock *dccp_v6_request_recv_sock(struct sock *sk,
625 newinet->daddr = newinet->saddr = newinet->rcv_saddr = LOOPBACK4_IPV6; 625 newinet->daddr = newinet->saddr = newinet->rcv_saddr = LOOPBACK4_IPV6;
626 626
627 __inet6_hash(newsk); 627 __inet6_hash(newsk);
628 inet_inherit_port(sk, newsk); 628 __inet_inherit_port(sk, newsk);
629 629
630 return newsk; 630 return newsk;
631 631
@@ -791,8 +791,8 @@ static int dccp_v6_rcv(struct sk_buff *skb)
791 791
792 /* Step 2: 792 /* Step 2:
793 * Look up flow ID in table and get corresponding socket */ 793 * Look up flow ID in table and get corresponding socket */
794 sk = __inet6_lookup(&init_net, &dccp_hashinfo, &ipv6_hdr(skb)->saddr, 794 sk = __inet6_lookup(dev_net(skb->dst->dev), &dccp_hashinfo,
795 dh->dccph_sport, 795 &ipv6_hdr(skb)->saddr, dh->dccph_sport,
796 &ipv6_hdr(skb)->daddr, ntohs(dh->dccph_dport), 796 &ipv6_hdr(skb)->daddr, ntohs(dh->dccph_dport),
797 inet6_iif(skb)); 797 inet6_iif(skb));
798 /* 798 /*
@@ -1102,8 +1102,6 @@ static struct timewait_sock_ops dccp6_timewait_sock_ops = {
1102 .twsk_obj_size = sizeof(struct dccp6_timewait_sock), 1102 .twsk_obj_size = sizeof(struct dccp6_timewait_sock),
1103}; 1103};
1104 1104
1105DEFINE_PROTO_INUSE(dccp_v6)
1106
1107static struct proto dccp_v6_prot = { 1105static struct proto dccp_v6_prot = {
1108 .name = "DCCPv6", 1106 .name = "DCCPv6",
1109 .owner = THIS_MODULE, 1107 .owner = THIS_MODULE,
@@ -1128,12 +1126,11 @@ static struct proto dccp_v6_prot = {
1128 .obj_size = sizeof(struct dccp6_sock), 1126 .obj_size = sizeof(struct dccp6_sock),
1129 .rsk_prot = &dccp6_request_sock_ops, 1127 .rsk_prot = &dccp6_request_sock_ops,
1130 .twsk_prot = &dccp6_timewait_sock_ops, 1128 .twsk_prot = &dccp6_timewait_sock_ops,
1131 .hashinfo = &dccp_hashinfo, 1129 .h.hashinfo = &dccp_hashinfo,
1132#ifdef CONFIG_COMPAT 1130#ifdef CONFIG_COMPAT
1133 .compat_setsockopt = compat_dccp_setsockopt, 1131 .compat_setsockopt = compat_dccp_setsockopt,
1134 .compat_getsockopt = compat_dccp_getsockopt, 1132 .compat_getsockopt = compat_dccp_getsockopt,
1135#endif 1133#endif
1136 REF_PROTO_INUSE(dccp_v6)
1137}; 1134};
1138 1135
1139static struct inet6_protocol dccp_v6_protocol = { 1136static struct inet6_protocol dccp_v6_protocol = {
@@ -1176,6 +1173,25 @@ static struct inet_protosw dccp_v6_protosw = {
1176 .flags = INET_PROTOSW_ICSK, 1173 .flags = INET_PROTOSW_ICSK,
1177}; 1174};
1178 1175
1176static int dccp_v6_init_net(struct net *net)
1177{
1178 int err;
1179
1180 err = inet_ctl_sock_create(&net->dccp.v6_ctl_sk, PF_INET6,
1181 SOCK_DCCP, IPPROTO_DCCP, net);
1182 return err;
1183}
1184
1185static void dccp_v6_exit_net(struct net *net)
1186{
1187 inet_ctl_sock_destroy(net->dccp.v6_ctl_sk);
1188}
1189
1190static struct pernet_operations dccp_v6_ops = {
1191 .init = dccp_v6_init_net,
1192 .exit = dccp_v6_exit_net,
1193};
1194
1179static int __init dccp_v6_init(void) 1195static int __init dccp_v6_init(void)
1180{ 1196{
1181 int err = proto_register(&dccp_v6_prot, 1); 1197 int err = proto_register(&dccp_v6_prot, 1);
@@ -1189,13 +1205,13 @@ static int __init dccp_v6_init(void)
1189 1205
1190 inet6_register_protosw(&dccp_v6_protosw); 1206 inet6_register_protosw(&dccp_v6_protosw);
1191 1207
1192 err = inet_csk_ctl_sock_create(&dccp_v6_ctl_socket, PF_INET6, 1208 err = register_pernet_subsys(&dccp_v6_ops);
1193 SOCK_DCCP, IPPROTO_DCCP);
1194 if (err != 0) 1209 if (err != 0)
1195 goto out_unregister_protosw; 1210 goto out_destroy_ctl_sock;
1196out: 1211out:
1197 return err; 1212 return err;
1198out_unregister_protosw: 1213
1214out_destroy_ctl_sock:
1199 inet6_del_protocol(&dccp_v6_protocol, IPPROTO_DCCP); 1215 inet6_del_protocol(&dccp_v6_protocol, IPPROTO_DCCP);
1200 inet6_unregister_protosw(&dccp_v6_protosw); 1216 inet6_unregister_protosw(&dccp_v6_protosw);
1201out_unregister_proto: 1217out_unregister_proto:
@@ -1205,6 +1221,7 @@ out_unregister_proto:
1205 1221
1206static void __exit dccp_v6_exit(void) 1222static void __exit dccp_v6_exit(void)
1207{ 1223{
1224 unregister_pernet_subsys(&dccp_v6_ops);
1208 inet6_del_protocol(&dccp_v6_protocol, IPPROTO_DCCP); 1225 inet6_del_protocol(&dccp_v6_protocol, IPPROTO_DCCP);
1209 inet6_unregister_protosw(&dccp_v6_protosw); 1226 inet6_unregister_protosw(&dccp_v6_protosw);
1210 proto_unregister(&dccp_v6_prot); 1227 proto_unregister(&dccp_v6_prot);