diff options
Diffstat (limited to 'net/dccp/ipv6.c')
-rw-r--r-- | net/dccp/ipv6.c | 93 |
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 */ |
37 | static struct socket *dccp_v6_ctl_socket; | ||
38 | 37 | ||
39 | static struct inet_connection_sock_af_ops dccp_ipv6_mapped; | 38 | static struct inet_connection_sock_af_ops dccp_ipv6_mapped; |
40 | static struct inet_connection_sock_af_ops dccp_ipv6_af_ops; | 39 | static 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 | ||
227 | static int dccp_v6_send_response(struct sock *sk, struct request_sock *req, | 227 | static 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 | ||
1105 | DEFINE_PROTO_INUSE(dccp_v6) | ||
1106 | |||
1107 | static struct proto dccp_v6_prot = { | 1105 | static 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 | ||
1139 | static struct inet6_protocol dccp_v6_protocol = { | 1136 | static 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 | ||
1176 | static 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 | |||
1185 | static void dccp_v6_exit_net(struct net *net) | ||
1186 | { | ||
1187 | inet_ctl_sock_destroy(net->dccp.v6_ctl_sk); | ||
1188 | } | ||
1189 | |||
1190 | static struct pernet_operations dccp_v6_ops = { | ||
1191 | .init = dccp_v6_init_net, | ||
1192 | .exit = dccp_v6_exit_net, | ||
1193 | }; | ||
1194 | |||
1179 | static int __init dccp_v6_init(void) | 1195 | static 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; |
1196 | out: | 1211 | out: |
1197 | return err; | 1212 | return err; |
1198 | out_unregister_protosw: | 1213 | |
1214 | out_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); |
1201 | out_unregister_proto: | 1217 | out_unregister_proto: |
@@ -1205,6 +1221,7 @@ out_unregister_proto: | |||
1205 | 1221 | ||
1206 | static void __exit dccp_v6_exit(void) | 1222 | static 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); |