diff options
Diffstat (limited to 'net/dccp/ipv6.c')
-rw-r--r-- | net/dccp/ipv6.c | 371 |
1 files changed, 196 insertions, 175 deletions
diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c index 80c4d048869e..65e2ab0886e6 100644 --- a/net/dccp/ipv6.c +++ b/net/dccp/ipv6.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * DCCP over IPv6 | 2 | * DCCP over IPv6 |
3 | * Linux INET6 implementation | 3 | * Linux INET6 implementation |
4 | * | 4 | * |
5 | * Based on net/dccp6/ipv6.c | 5 | * Based on net/dccp6/ipv6.c |
6 | * | 6 | * |
@@ -33,6 +33,9 @@ | |||
33 | #include "dccp.h" | 33 | #include "dccp.h" |
34 | #include "ipv6.h" | 34 | #include "ipv6.h" |
35 | 35 | ||
36 | /* Socket used for sending RSTs and ACKs */ | ||
37 | static struct socket *dccp_v6_ctl_socket; | ||
38 | |||
36 | static void dccp_v6_ctl_send_reset(struct sk_buff *skb); | 39 | static void dccp_v6_ctl_send_reset(struct sk_buff *skb); |
37 | static void dccp_v6_reqsk_send_ack(struct sk_buff *skb, | 40 | static void dccp_v6_reqsk_send_ack(struct sk_buff *skb, |
38 | struct request_sock *req); | 41 | struct request_sock *req); |
@@ -53,7 +56,7 @@ static void dccp_v6_hash(struct sock *sk) | |||
53 | { | 56 | { |
54 | if (sk->sk_state != DCCP_CLOSED) { | 57 | if (sk->sk_state != DCCP_CLOSED) { |
55 | if (inet_csk(sk)->icsk_af_ops == &dccp_ipv6_mapped) { | 58 | if (inet_csk(sk)->icsk_af_ops == &dccp_ipv6_mapped) { |
56 | dccp_prot.hash(sk); | 59 | dccp_hash(sk); |
57 | return; | 60 | return; |
58 | } | 61 | } |
59 | local_bh_disable(); | 62 | local_bh_disable(); |
@@ -63,8 +66,8 @@ static void dccp_v6_hash(struct sock *sk) | |||
63 | } | 66 | } |
64 | 67 | ||
65 | static inline u16 dccp_v6_check(struct dccp_hdr *dh, int len, | 68 | static inline u16 dccp_v6_check(struct dccp_hdr *dh, int len, |
66 | struct in6_addr *saddr, | 69 | struct in6_addr *saddr, |
67 | struct in6_addr *daddr, | 70 | struct in6_addr *daddr, |
68 | unsigned long base) | 71 | unsigned long base) |
69 | { | 72 | { |
70 | return csum_ipv6_magic(saddr, daddr, len, IPPROTO_DCCP, base); | 73 | return csum_ipv6_magic(saddr, daddr, len, IPPROTO_DCCP, base); |
@@ -79,17 +82,17 @@ static __u32 dccp_v6_init_sequence(struct sock *sk, struct sk_buff *skb) | |||
79 | skb->nh.ipv6h->saddr.s6_addr32, | 82 | skb->nh.ipv6h->saddr.s6_addr32, |
80 | dh->dccph_dport, | 83 | dh->dccph_dport, |
81 | dh->dccph_sport); | 84 | dh->dccph_sport); |
82 | else | 85 | |
83 | return secure_dccp_sequence_number(skb->nh.iph->daddr, | 86 | return secure_dccp_sequence_number(skb->nh.iph->daddr, |
84 | skb->nh.iph->saddr, | 87 | skb->nh.iph->saddr, |
85 | dh->dccph_dport, | 88 | dh->dccph_dport, |
86 | dh->dccph_sport); | 89 | dh->dccph_sport); |
87 | } | 90 | } |
88 | 91 | ||
89 | static int dccp_v6_connect(struct sock *sk, struct sockaddr *uaddr, | 92 | static int dccp_v6_connect(struct sock *sk, struct sockaddr *uaddr, |
90 | int addr_len) | 93 | int addr_len) |
91 | { | 94 | { |
92 | struct sockaddr_in6 *usin = (struct sockaddr_in6 *) uaddr; | 95 | struct sockaddr_in6 *usin = (struct sockaddr_in6 *)uaddr; |
93 | struct inet_connection_sock *icsk = inet_csk(sk); | 96 | struct inet_connection_sock *icsk = inet_csk(sk); |
94 | struct inet_sock *inet = inet_sk(sk); | 97 | struct inet_sock *inet = inet_sk(sk); |
95 | struct ipv6_pinfo *np = inet6_sk(sk); | 98 | struct ipv6_pinfo *np = inet6_sk(sk); |
@@ -102,10 +105,10 @@ static int dccp_v6_connect(struct sock *sk, struct sockaddr *uaddr, | |||
102 | 105 | ||
103 | dp->dccps_role = DCCP_ROLE_CLIENT; | 106 | dp->dccps_role = DCCP_ROLE_CLIENT; |
104 | 107 | ||
105 | if (addr_len < SIN6_LEN_RFC2133) | 108 | if (addr_len < SIN6_LEN_RFC2133) |
106 | return -EINVAL; | 109 | return -EINVAL; |
107 | 110 | ||
108 | if (usin->sin6_family != AF_INET6) | 111 | if (usin->sin6_family != AF_INET6) |
109 | return -EAFNOSUPPORT; | 112 | return -EAFNOSUPPORT; |
110 | 113 | ||
111 | memset(&fl, 0, sizeof(fl)); | 114 | memset(&fl, 0, sizeof(fl)); |
@@ -122,17 +125,15 @@ static int dccp_v6_connect(struct sock *sk, struct sockaddr *uaddr, | |||
122 | fl6_sock_release(flowlabel); | 125 | fl6_sock_release(flowlabel); |
123 | } | 126 | } |
124 | } | 127 | } |
125 | |||
126 | /* | 128 | /* |
127 | * connect() to INADDR_ANY means loopback (BSD'ism). | 129 | * connect() to INADDR_ANY means loopback (BSD'ism). |
128 | */ | 130 | */ |
129 | 131 | if (ipv6_addr_any(&usin->sin6_addr)) | |
130 | if (ipv6_addr_any(&usin->sin6_addr)) | 132 | usin->sin6_addr.s6_addr[15] = 1; |
131 | usin->sin6_addr.s6_addr[15] = 0x1; | ||
132 | 133 | ||
133 | addr_type = ipv6_addr_type(&usin->sin6_addr); | 134 | addr_type = ipv6_addr_type(&usin->sin6_addr); |
134 | 135 | ||
135 | if(addr_type & IPV6_ADDR_MULTICAST) | 136 | if (addr_type & IPV6_ADDR_MULTICAST) |
136 | return -ENETUNREACH; | 137 | return -ENETUNREACH; |
137 | 138 | ||
138 | if (addr_type & IPV6_ADDR_LINKLOCAL) { | 139 | if (addr_type & IPV6_ADDR_LINKLOCAL) { |
@@ -157,9 +158,8 @@ static int dccp_v6_connect(struct sock *sk, struct sockaddr *uaddr, | |||
157 | np->flow_label = fl.fl6_flowlabel; | 158 | np->flow_label = fl.fl6_flowlabel; |
158 | 159 | ||
159 | /* | 160 | /* |
160 | * DCCP over IPv4 | 161 | * DCCP over IPv4 |
161 | */ | 162 | */ |
162 | |||
163 | if (addr_type == IPV6_ADDR_MAPPED) { | 163 | if (addr_type == IPV6_ADDR_MAPPED) { |
164 | u32 exthdrlen = icsk->icsk_ext_hdr_len; | 164 | u32 exthdrlen = icsk->icsk_ext_hdr_len; |
165 | struct sockaddr_in sin; | 165 | struct sockaddr_in sin; |
@@ -177,7 +177,6 @@ static int dccp_v6_connect(struct sock *sk, struct sockaddr *uaddr, | |||
177 | sk->sk_backlog_rcv = dccp_v4_do_rcv; | 177 | sk->sk_backlog_rcv = dccp_v4_do_rcv; |
178 | 178 | ||
179 | err = dccp_v4_connect(sk, (struct sockaddr *)&sin, sizeof(sin)); | 179 | err = dccp_v4_connect(sk, (struct sockaddr *)&sin, sizeof(sin)); |
180 | |||
181 | if (err) { | 180 | if (err) { |
182 | icsk->icsk_ext_hdr_len = exthdrlen; | 181 | icsk->icsk_ext_hdr_len = exthdrlen; |
183 | icsk->icsk_af_ops = &dccp_ipv6_af_ops; | 182 | icsk->icsk_af_ops = &dccp_ipv6_af_ops; |
@@ -203,8 +202,9 @@ static int dccp_v6_connect(struct sock *sk, struct sockaddr *uaddr, | |||
203 | fl.fl_ip_dport = usin->sin6_port; | 202 | fl.fl_ip_dport = usin->sin6_port; |
204 | fl.fl_ip_sport = inet->sport; | 203 | fl.fl_ip_sport = inet->sport; |
205 | 204 | ||
206 | if (np->opt && np->opt->srcrt) { | 205 | if (np->opt != NULL && np->opt->srcrt != NULL) { |
207 | struct rt0_hdr *rt0 = (struct rt0_hdr *)np->opt->srcrt; | 206 | const struct rt0_hdr *rt0 = (struct rt0_hdr *)np->opt->srcrt; |
207 | |||
208 | ipv6_addr_copy(&final, &fl.fl6_dst); | 208 | ipv6_addr_copy(&final, &fl.fl6_dst); |
209 | ipv6_addr_copy(&fl.fl6_dst, rt0->addr); | 209 | ipv6_addr_copy(&fl.fl6_dst, rt0->addr); |
210 | final_p = &final; | 210 | final_p = &final; |
@@ -213,10 +213,12 @@ static int dccp_v6_connect(struct sock *sk, struct sockaddr *uaddr, | |||
213 | err = ip6_dst_lookup(sk, &dst, &fl); | 213 | err = ip6_dst_lookup(sk, &dst, &fl); |
214 | if (err) | 214 | if (err) |
215 | goto failure; | 215 | goto failure; |
216 | |||
216 | if (final_p) | 217 | if (final_p) |
217 | ipv6_addr_copy(&fl.fl6_dst, final_p); | 218 | ipv6_addr_copy(&fl.fl6_dst, final_p); |
218 | 219 | ||
219 | if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0) | 220 | err = xfrm_lookup(&dst, &fl, sk, 0); |
221 | if (err < 0) | ||
220 | goto failure; | 222 | goto failure; |
221 | 223 | ||
222 | if (saddr == NULL) { | 224 | if (saddr == NULL) { |
@@ -231,7 +233,7 @@ static int dccp_v6_connect(struct sock *sk, struct sockaddr *uaddr, | |||
231 | ip6_dst_store(sk, dst, NULL); | 233 | ip6_dst_store(sk, dst, NULL); |
232 | 234 | ||
233 | icsk->icsk_ext_hdr_len = 0; | 235 | icsk->icsk_ext_hdr_len = 0; |
234 | if (np->opt) | 236 | if (np->opt != NULL) |
235 | icsk->icsk_ext_hdr_len = (np->opt->opt_flen + | 237 | icsk->icsk_ext_hdr_len = (np->opt->opt_flen + |
236 | np->opt->opt_nflen); | 238 | np->opt->opt_nflen); |
237 | 239 | ||
@@ -264,7 +266,7 @@ failure: | |||
264 | } | 266 | } |
265 | 267 | ||
266 | static void dccp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | 268 | static void dccp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, |
267 | int type, int code, int offset, __u32 info) | 269 | int type, int code, int offset, __be32 info) |
268 | { | 270 | { |
269 | struct ipv6hdr *hdr = (struct ipv6hdr *)skb->data; | 271 | struct ipv6hdr *hdr = (struct ipv6hdr *)skb->data; |
270 | const struct dccp_hdr *dh = (struct dccp_hdr *)(skb->data + offset); | 272 | const struct dccp_hdr *dh = (struct dccp_hdr *)(skb->data + offset); |
@@ -305,7 +307,6 @@ static void dccp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | |||
305 | 307 | ||
306 | /* icmp should have updated the destination cache entry */ | 308 | /* icmp should have updated the destination cache entry */ |
307 | dst = __sk_dst_check(sk, np->dst_cookie); | 309 | dst = __sk_dst_check(sk, np->dst_cookie); |
308 | |||
309 | if (dst == NULL) { | 310 | if (dst == NULL) { |
310 | struct inet_sock *inet = inet_sk(sk); | 311 | struct inet_sock *inet = inet_sk(sk); |
311 | struct flowi fl; | 312 | struct flowi fl; |
@@ -322,16 +323,17 @@ static void dccp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | |||
322 | fl.fl_ip_dport = inet->dport; | 323 | fl.fl_ip_dport = inet->dport; |
323 | fl.fl_ip_sport = inet->sport; | 324 | fl.fl_ip_sport = inet->sport; |
324 | 325 | ||
325 | if ((err = ip6_dst_lookup(sk, &dst, &fl))) { | 326 | err = ip6_dst_lookup(sk, &dst, &fl); |
327 | if (err) { | ||
326 | sk->sk_err_soft = -err; | 328 | sk->sk_err_soft = -err; |
327 | goto out; | 329 | goto out; |
328 | } | 330 | } |
329 | 331 | ||
330 | if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0) { | 332 | err = xfrm_lookup(&dst, &fl, sk, 0); |
333 | if (err < 0) { | ||
331 | sk->sk_err_soft = -err; | 334 | sk->sk_err_soft = -err; |
332 | goto out; | 335 | goto out; |
333 | } | 336 | } |
334 | |||
335 | } else | 337 | } else |
336 | dst_hold(dst); | 338 | dst_hold(dst); |
337 | 339 | ||
@@ -355,11 +357,12 @@ static void dccp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | |||
355 | req = inet6_csk_search_req(sk, &prev, dh->dccph_dport, | 357 | req = inet6_csk_search_req(sk, &prev, dh->dccph_dport, |
356 | &hdr->daddr, &hdr->saddr, | 358 | &hdr->daddr, &hdr->saddr, |
357 | inet6_iif(skb)); | 359 | inet6_iif(skb)); |
358 | if (!req) | 360 | if (req == NULL) |
359 | goto out; | 361 | goto out; |
360 | 362 | ||
361 | /* ICMPs are not backlogged, hence we cannot get | 363 | /* |
362 | * an established socket here. | 364 | * ICMPs are not backlogged, hence we cannot get an established |
365 | * socket here. | ||
363 | */ | 366 | */ |
364 | BUG_TRAP(req->sk == NULL); | 367 | BUG_TRAP(req->sk == NULL); |
365 | 368 | ||
@@ -373,7 +376,7 @@ static void dccp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | |||
373 | 376 | ||
374 | case DCCP_REQUESTING: | 377 | case DCCP_REQUESTING: |
375 | case DCCP_RESPOND: /* Cannot happen. | 378 | case DCCP_RESPOND: /* Cannot happen. |
376 | It can, it SYNs are crossed. --ANK */ | 379 | It can, it SYNs are crossed. --ANK */ |
377 | if (!sock_owned_by_user(sk)) { | 380 | if (!sock_owned_by_user(sk)) { |
378 | DCCP_INC_STATS_BH(DCCP_MIB_ATTEMPTFAILS); | 381 | DCCP_INC_STATS_BH(DCCP_MIB_ATTEMPTFAILS); |
379 | sk->sk_err = err; | 382 | sk->sk_err = err; |
@@ -382,7 +385,6 @@ static void dccp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | |||
382 | * (see connect in sock.c) | 385 | * (see connect in sock.c) |
383 | */ | 386 | */ |
384 | sk->sk_error_report(sk); | 387 | sk->sk_error_report(sk); |
385 | |||
386 | dccp_done(sk); | 388 | dccp_done(sk); |
387 | } else | 389 | } else |
388 | sk->sk_err_soft = err; | 390 | sk->sk_err_soft = err; |
@@ -428,14 +430,16 @@ static int dccp_v6_send_response(struct sock *sk, struct request_sock *req, | |||
428 | ireq6->pktopts) { | 430 | ireq6->pktopts) { |
429 | struct sk_buff *pktopts = ireq6->pktopts; | 431 | struct sk_buff *pktopts = ireq6->pktopts; |
430 | struct inet6_skb_parm *rxopt = IP6CB(pktopts); | 432 | struct inet6_skb_parm *rxopt = IP6CB(pktopts); |
433 | |||
431 | if (rxopt->srcrt) | 434 | if (rxopt->srcrt) |
432 | opt = ipv6_invert_rthdr(sk, | 435 | opt = ipv6_invert_rthdr(sk, |
433 | (struct ipv6_rt_hdr *)(pktopts->nh.raw + | 436 | (struct ipv6_rt_hdr *)(pktopts->nh.raw + |
434 | rxopt->srcrt)); | 437 | rxopt->srcrt)); |
435 | } | 438 | } |
436 | 439 | ||
437 | if (opt && opt->srcrt) { | 440 | if (opt != NULL && opt->srcrt != NULL) { |
438 | struct rt0_hdr *rt0 = (struct rt0_hdr *)opt->srcrt; | 441 | const struct rt0_hdr *rt0 = (struct rt0_hdr *)opt->srcrt; |
442 | |||
439 | ipv6_addr_copy(&final, &fl.fl6_dst); | 443 | ipv6_addr_copy(&final, &fl.fl6_dst); |
440 | ipv6_addr_copy(&fl.fl6_dst, rt0->addr); | 444 | ipv6_addr_copy(&fl.fl6_dst, rt0->addr); |
441 | final_p = &final; | 445 | final_p = &final; |
@@ -444,15 +448,19 @@ static int dccp_v6_send_response(struct sock *sk, struct request_sock *req, | |||
444 | err = ip6_dst_lookup(sk, &dst, &fl); | 448 | err = ip6_dst_lookup(sk, &dst, &fl); |
445 | if (err) | 449 | if (err) |
446 | goto done; | 450 | goto done; |
451 | |||
447 | if (final_p) | 452 | if (final_p) |
448 | ipv6_addr_copy(&fl.fl6_dst, final_p); | 453 | ipv6_addr_copy(&fl.fl6_dst, final_p); |
449 | if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0) | 454 | |
455 | err = xfrm_lookup(&dst, &fl, sk, 0); | ||
456 | if (err < 0) | ||
450 | goto done; | 457 | goto done; |
451 | } | 458 | } |
452 | 459 | ||
453 | skb = dccp_make_response(sk, dst, req); | 460 | skb = dccp_make_response(sk, dst, req); |
454 | if (skb != NULL) { | 461 | if (skb != NULL) { |
455 | struct dccp_hdr *dh = dccp_hdr(skb); | 462 | struct dccp_hdr *dh = dccp_hdr(skb); |
463 | |||
456 | dh->dccph_checksum = dccp_v6_check(dh, skb->len, | 464 | dh->dccph_checksum = dccp_v6_check(dh, skb->len, |
457 | &ireq6->loc_addr, | 465 | &ireq6->loc_addr, |
458 | &ireq6->rmt_addr, | 466 | &ireq6->rmt_addr, |
@@ -466,7 +474,7 @@ static int dccp_v6_send_response(struct sock *sk, struct request_sock *req, | |||
466 | } | 474 | } |
467 | 475 | ||
468 | done: | 476 | done: |
469 | if (opt && opt != np->opt) | 477 | if (opt != NULL && opt != np->opt) |
470 | sock_kfree_s(sk, opt, opt->tot_len); | 478 | sock_kfree_s(sk, opt, opt->tot_len); |
471 | dst_release(dst); | 479 | dst_release(dst); |
472 | return err; | 480 | return err; |
@@ -497,7 +505,7 @@ static void dccp_v6_send_check(struct sock *sk, int len, struct sk_buff *skb) | |||
497 | struct dccp_hdr *dh = dccp_hdr(skb); | 505 | struct dccp_hdr *dh = dccp_hdr(skb); |
498 | 506 | ||
499 | dh->dccph_checksum = csum_ipv6_magic(&np->saddr, &np->daddr, | 507 | dh->dccph_checksum = csum_ipv6_magic(&np->saddr, &np->daddr, |
500 | len, IPPROTO_DCCP, | 508 | len, IPPROTO_DCCP, |
501 | csum_partial((char *)dh, | 509 | csum_partial((char *)dh, |
502 | dh->dccph_doff << 2, | 510 | dh->dccph_doff << 2, |
503 | skb->csum)); | 511 | skb->csum)); |
@@ -505,8 +513,8 @@ static void dccp_v6_send_check(struct sock *sk, int len, struct sk_buff *skb) | |||
505 | 513 | ||
506 | static void dccp_v6_ctl_send_reset(struct sk_buff *rxskb) | 514 | static void dccp_v6_ctl_send_reset(struct sk_buff *rxskb) |
507 | { | 515 | { |
508 | struct dccp_hdr *rxdh = dccp_hdr(rxskb), *dh; | 516 | struct dccp_hdr *rxdh = dccp_hdr(rxskb), *dh; |
509 | const int dccp_hdr_reset_len = sizeof(struct dccp_hdr) + | 517 | const u32 dccp_hdr_reset_len = sizeof(struct dccp_hdr) + |
510 | sizeof(struct dccp_hdr_ext) + | 518 | sizeof(struct dccp_hdr_ext) + |
511 | sizeof(struct dccp_hdr_reset); | 519 | sizeof(struct dccp_hdr_reset); |
512 | struct sk_buff *skb; | 520 | struct sk_buff *skb; |
@@ -517,20 +525,14 @@ static void dccp_v6_ctl_send_reset(struct sk_buff *rxskb) | |||
517 | return; | 525 | return; |
518 | 526 | ||
519 | if (!ipv6_unicast_destination(rxskb)) | 527 | if (!ipv6_unicast_destination(rxskb)) |
520 | return; | 528 | return; |
521 | |||
522 | /* | ||
523 | * We need to grab some memory, and put together an RST, | ||
524 | * and then put it into the queue to be sent. | ||
525 | */ | ||
526 | 529 | ||
527 | skb = alloc_skb(MAX_HEADER + sizeof(struct ipv6hdr) + | 530 | skb = alloc_skb(dccp_v6_ctl_socket->sk->sk_prot->max_header, |
528 | dccp_hdr_reset_len, GFP_ATOMIC); | 531 | GFP_ATOMIC); |
529 | if (skb == NULL) | 532 | if (skb == NULL) |
530 | return; | 533 | return; |
531 | 534 | ||
532 | skb_reserve(skb, MAX_HEADER + sizeof(struct ipv6hdr) + | 535 | skb_reserve(skb, dccp_v6_ctl_socket->sk->sk_prot->max_header); |
533 | dccp_hdr_reset_len); | ||
534 | 536 | ||
535 | skb->h.raw = skb_push(skb, dccp_hdr_reset_len); | 537 | skb->h.raw = skb_push(skb, dccp_hdr_reset_len); |
536 | dh = dccp_hdr(skb); | 538 | dh = dccp_hdr(skb); |
@@ -568,7 +570,7 @@ static void dccp_v6_ctl_send_reset(struct sk_buff *rxskb) | |||
568 | /* sk = NULL, but it is safe for now. RST socket required. */ | 570 | /* sk = NULL, but it is safe for now. RST socket required. */ |
569 | if (!ip6_dst_lookup(NULL, &skb->dst, &fl)) { | 571 | if (!ip6_dst_lookup(NULL, &skb->dst, &fl)) { |
570 | if (xfrm_lookup(&skb->dst, &fl, NULL, 0) >= 0) { | 572 | if (xfrm_lookup(&skb->dst, &fl, NULL, 0) >= 0) { |
571 | ip6_xmit(NULL, skb, &fl, NULL, 0); | 573 | ip6_xmit(dccp_v6_ctl_socket->sk, skb, &fl, NULL, 0); |
572 | DCCP_INC_STATS_BH(DCCP_MIB_OUTSEGS); | 574 | DCCP_INC_STATS_BH(DCCP_MIB_OUTSEGS); |
573 | DCCP_INC_STATS_BH(DCCP_MIB_OUTRSTS); | 575 | DCCP_INC_STATS_BH(DCCP_MIB_OUTRSTS); |
574 | return; | 576 | return; |
@@ -578,22 +580,22 @@ static void dccp_v6_ctl_send_reset(struct sk_buff *rxskb) | |||
578 | kfree_skb(skb); | 580 | kfree_skb(skb); |
579 | } | 581 | } |
580 | 582 | ||
581 | static void dccp_v6_ctl_send_ack(struct sk_buff *rxskb) | 583 | static void dccp_v6_reqsk_send_ack(struct sk_buff *rxskb, |
584 | struct request_sock *req) | ||
582 | { | 585 | { |
583 | struct flowi fl; | 586 | struct flowi fl; |
584 | struct dccp_hdr *rxdh = dccp_hdr(rxskb), *dh; | 587 | struct dccp_hdr *rxdh = dccp_hdr(rxskb), *dh; |
585 | const int dccp_hdr_ack_len = sizeof(struct dccp_hdr) + | 588 | const u32 dccp_hdr_ack_len = sizeof(struct dccp_hdr) + |
586 | sizeof(struct dccp_hdr_ext) + | 589 | sizeof(struct dccp_hdr_ext) + |
587 | sizeof(struct dccp_hdr_ack_bits); | 590 | sizeof(struct dccp_hdr_ack_bits); |
588 | struct sk_buff *skb; | 591 | struct sk_buff *skb; |
589 | 592 | ||
590 | skb = alloc_skb(MAX_HEADER + sizeof(struct ipv6hdr) + | 593 | skb = alloc_skb(dccp_v6_ctl_socket->sk->sk_prot->max_header, |
591 | dccp_hdr_ack_len, GFP_ATOMIC); | 594 | GFP_ATOMIC); |
592 | if (skb == NULL) | 595 | if (skb == NULL) |
593 | return; | 596 | return; |
594 | 597 | ||
595 | skb_reserve(skb, MAX_HEADER + sizeof(struct ipv6hdr) + | 598 | skb_reserve(skb, dccp_v6_ctl_socket->sk->sk_prot->max_header); |
596 | dccp_hdr_ack_len); | ||
597 | 599 | ||
598 | skb->h.raw = skb_push(skb, dccp_hdr_ack_len); | 600 | skb->h.raw = skb_push(skb, dccp_hdr_ack_len); |
599 | dh = dccp_hdr(skb); | 601 | dh = dccp_hdr(skb); |
@@ -605,7 +607,7 @@ static void dccp_v6_ctl_send_ack(struct sk_buff *rxskb) | |||
605 | dh->dccph_dport = rxdh->dccph_sport; | 607 | dh->dccph_dport = rxdh->dccph_sport; |
606 | dh->dccph_doff = dccp_hdr_ack_len / 4; | 608 | dh->dccph_doff = dccp_hdr_ack_len / 4; |
607 | dh->dccph_x = 1; | 609 | dh->dccph_x = 1; |
608 | 610 | ||
609 | dccp_hdr_set_seq(dh, DCCP_SKB_CB(rxskb)->dccpd_ack_seq); | 611 | dccp_hdr_set_seq(dh, DCCP_SKB_CB(rxskb)->dccpd_ack_seq); |
610 | dccp_hdr_set_ack(dccp_hdr_ack_bits(skb), | 612 | dccp_hdr_set_ack(dccp_hdr_ack_bits(skb), |
611 | DCCP_SKB_CB(rxskb)->dccpd_seq); | 613 | DCCP_SKB_CB(rxskb)->dccpd_seq); |
@@ -623,7 +625,7 @@ static void dccp_v6_ctl_send_ack(struct sk_buff *rxskb) | |||
623 | 625 | ||
624 | if (!ip6_dst_lookup(NULL, &skb->dst, &fl)) { | 626 | if (!ip6_dst_lookup(NULL, &skb->dst, &fl)) { |
625 | if (xfrm_lookup(&skb->dst, &fl, NULL, 0) >= 0) { | 627 | if (xfrm_lookup(&skb->dst, &fl, NULL, 0) >= 0) { |
626 | ip6_xmit(NULL, skb, &fl, NULL, 0); | 628 | ip6_xmit(dccp_v6_ctl_socket->sk, skb, &fl, NULL, 0); |
627 | DCCP_INC_STATS_BH(DCCP_MIB_OUTSEGS); | 629 | DCCP_INC_STATS_BH(DCCP_MIB_OUTSEGS); |
628 | return; | 630 | return; |
629 | } | 631 | } |
@@ -632,12 +634,6 @@ static void dccp_v6_ctl_send_ack(struct sk_buff *rxskb) | |||
632 | kfree_skb(skb); | 634 | kfree_skb(skb); |
633 | } | 635 | } |
634 | 636 | ||
635 | static void dccp_v6_reqsk_send_ack(struct sk_buff *skb, | ||
636 | struct request_sock *req) | ||
637 | { | ||
638 | dccp_v6_ctl_send_ack(skb); | ||
639 | } | ||
640 | |||
641 | static struct sock *dccp_v6_hnd_req(struct sock *sk,struct sk_buff *skb) | 637 | static struct sock *dccp_v6_hnd_req(struct sock *sk,struct sk_buff *skb) |
642 | { | 638 | { |
643 | const struct dccp_hdr *dh = dccp_hdr(skb); | 639 | const struct dccp_hdr *dh = dccp_hdr(skb); |
@@ -657,7 +653,6 @@ static struct sock *dccp_v6_hnd_req(struct sock *sk,struct sk_buff *skb) | |||
657 | &iph->saddr, dh->dccph_sport, | 653 | &iph->saddr, dh->dccph_sport, |
658 | &iph->daddr, ntohs(dh->dccph_dport), | 654 | &iph->daddr, ntohs(dh->dccph_dport), |
659 | inet6_iif(skb)); | 655 | inet6_iif(skb)); |
660 | |||
661 | if (nsk != NULL) { | 656 | if (nsk != NULL) { |
662 | if (nsk->sk_state != DCCP_TIME_WAIT) { | 657 | if (nsk->sk_state != DCCP_TIME_WAIT) { |
663 | bh_lock_sock(nsk); | 658 | bh_lock_sock(nsk); |
@@ -678,7 +673,7 @@ static int dccp_v6_conn_request(struct sock *sk, struct sk_buff *skb) | |||
678 | struct dccp_request_sock *dreq; | 673 | struct dccp_request_sock *dreq; |
679 | struct inet6_request_sock *ireq6; | 674 | struct inet6_request_sock *ireq6; |
680 | struct ipv6_pinfo *np = inet6_sk(sk); | 675 | struct ipv6_pinfo *np = inet6_sk(sk); |
681 | const __u32 service = dccp_hdr_request(skb)->dccph_req_service; | 676 | const __be32 service = dccp_hdr_request(skb)->dccph_req_service; |
682 | struct dccp_skb_cb *dcb = DCCP_SKB_CB(skb); | 677 | struct dccp_skb_cb *dcb = DCCP_SKB_CB(skb); |
683 | __u8 reset_code = DCCP_RESET_CODE_TOO_BUSY; | 678 | __u8 reset_code = DCCP_RESET_CODE_TOO_BUSY; |
684 | 679 | ||
@@ -686,17 +681,17 @@ static int dccp_v6_conn_request(struct sock *sk, struct sk_buff *skb) | |||
686 | return dccp_v4_conn_request(sk, skb); | 681 | return dccp_v4_conn_request(sk, skb); |
687 | 682 | ||
688 | if (!ipv6_unicast_destination(skb)) | 683 | if (!ipv6_unicast_destination(skb)) |
689 | goto drop; | 684 | goto drop; |
690 | 685 | ||
691 | if (dccp_bad_service_code(sk, service)) { | 686 | if (dccp_bad_service_code(sk, service)) { |
692 | reset_code = DCCP_RESET_CODE_BAD_SERVICE_CODE; | 687 | reset_code = DCCP_RESET_CODE_BAD_SERVICE_CODE; |
693 | goto drop; | 688 | goto drop; |
694 | } | 689 | } |
695 | /* | 690 | /* |
696 | * There are no SYN attacks on IPv6, yet... | 691 | * There are no SYN attacks on IPv6, yet... |
697 | */ | 692 | */ |
698 | if (inet_csk_reqsk_queue_is_full(sk)) | 693 | if (inet_csk_reqsk_queue_is_full(sk)) |
699 | goto drop; | 694 | goto drop; |
700 | 695 | ||
701 | if (sk_acceptq_is_full(sk) && inet_csk_reqsk_queue_young(sk) > 1) | 696 | if (sk_acceptq_is_full(sk) && inet_csk_reqsk_queue_young(sk) > 1) |
702 | goto drop; | 697 | goto drop; |
@@ -730,7 +725,7 @@ static int dccp_v6_conn_request(struct sock *sk, struct sk_buff *skb) | |||
730 | ipv6_addr_type(&ireq6->rmt_addr) & IPV6_ADDR_LINKLOCAL) | 725 | ipv6_addr_type(&ireq6->rmt_addr) & IPV6_ADDR_LINKLOCAL) |
731 | ireq6->iif = inet6_iif(skb); | 726 | ireq6->iif = inet6_iif(skb); |
732 | 727 | ||
733 | /* | 728 | /* |
734 | * Step 3: Process LISTEN state | 729 | * Step 3: Process LISTEN state |
735 | * | 730 | * |
736 | * Set S.ISR, S.GSR, S.SWL, S.SWH from packet or Init Cookie | 731 | * Set S.ISR, S.GSR, S.SWL, S.SWH from packet or Init Cookie |
@@ -774,9 +769,8 @@ static struct sock *dccp_v6_request_recv_sock(struct sock *sk, | |||
774 | /* | 769 | /* |
775 | * v6 mapped | 770 | * v6 mapped |
776 | */ | 771 | */ |
777 | |||
778 | newsk = dccp_v4_request_recv_sock(sk, skb, req, dst); | 772 | newsk = dccp_v4_request_recv_sock(sk, skb, req, dst); |
779 | if (newsk == NULL) | 773 | if (newsk == NULL) |
780 | return NULL; | 774 | return NULL; |
781 | 775 | ||
782 | newdp6 = (struct dccp6_sock *)newsk; | 776 | newdp6 = (struct dccp6_sock *)newsk; |
@@ -822,9 +816,9 @@ static struct sock *dccp_v6_request_recv_sock(struct sock *sk, | |||
822 | if (sk_acceptq_is_full(sk)) | 816 | if (sk_acceptq_is_full(sk)) |
823 | goto out_overflow; | 817 | goto out_overflow; |
824 | 818 | ||
825 | if (np->rxopt.bits.osrcrt == 2 && | 819 | if (np->rxopt.bits.osrcrt == 2 && opt == NULL && ireq6->pktopts) { |
826 | opt == NULL && ireq6->pktopts) { | 820 | const struct inet6_skb_parm *rxopt = IP6CB(ireq6->pktopts); |
827 | struct inet6_skb_parm *rxopt = IP6CB(ireq6->pktopts); | 821 | |
828 | if (rxopt->srcrt) | 822 | if (rxopt->srcrt) |
829 | opt = ipv6_invert_rthdr(sk, | 823 | opt = ipv6_invert_rthdr(sk, |
830 | (struct ipv6_rt_hdr *)(ireq6->pktopts->nh.raw + | 824 | (struct ipv6_rt_hdr *)(ireq6->pktopts->nh.raw + |
@@ -838,8 +832,9 @@ static struct sock *dccp_v6_request_recv_sock(struct sock *sk, | |||
838 | memset(&fl, 0, sizeof(fl)); | 832 | memset(&fl, 0, sizeof(fl)); |
839 | fl.proto = IPPROTO_DCCP; | 833 | fl.proto = IPPROTO_DCCP; |
840 | ipv6_addr_copy(&fl.fl6_dst, &ireq6->rmt_addr); | 834 | ipv6_addr_copy(&fl.fl6_dst, &ireq6->rmt_addr); |
841 | if (opt && opt->srcrt) { | 835 | if (opt != NULL && opt->srcrt != NULL) { |
842 | struct rt0_hdr *rt0 = (struct rt0_hdr *) opt->srcrt; | 836 | const struct rt0_hdr *rt0 = (struct rt0_hdr *)opt->srcrt; |
837 | |||
843 | ipv6_addr_copy(&final, &fl.fl6_dst); | 838 | ipv6_addr_copy(&final, &fl.fl6_dst); |
844 | ipv6_addr_copy(&fl.fl6_dst, rt0->addr); | 839 | ipv6_addr_copy(&fl.fl6_dst, rt0->addr); |
845 | final_p = &final; | 840 | final_p = &final; |
@@ -857,7 +852,7 @@ static struct sock *dccp_v6_request_recv_sock(struct sock *sk, | |||
857 | 852 | ||
858 | if ((xfrm_lookup(&dst, &fl, sk, 0)) < 0) | 853 | if ((xfrm_lookup(&dst, &fl, sk, 0)) < 0) |
859 | goto out; | 854 | goto out; |
860 | } | 855 | } |
861 | 856 | ||
862 | newsk = dccp_create_openreq_child(sk, req, skb); | 857 | newsk = dccp_create_openreq_child(sk, req, skb); |
863 | if (newsk == NULL) | 858 | if (newsk == NULL) |
@@ -870,9 +865,8 @@ static struct sock *dccp_v6_request_recv_sock(struct sock *sk, | |||
870 | */ | 865 | */ |
871 | 866 | ||
872 | ip6_dst_store(newsk, dst, NULL); | 867 | ip6_dst_store(newsk, dst, NULL); |
873 | newsk->sk_route_caps = dst->dev->features & | 868 | newsk->sk_route_caps = dst->dev->features & ~(NETIF_F_IP_CSUM | |
874 | ~(NETIF_F_IP_CSUM | NETIF_F_TSO); | 869 | NETIF_F_TSO); |
875 | |||
876 | newdp6 = (struct dccp6_sock *)newsk; | 870 | newdp6 = (struct dccp6_sock *)newsk; |
877 | newinet = inet_sk(newsk); | 871 | newinet = inet_sk(newsk); |
878 | newinet->pinet6 = &newdp6->inet6; | 872 | newinet->pinet6 = &newdp6->inet6; |
@@ -886,7 +880,7 @@ static struct sock *dccp_v6_request_recv_sock(struct sock *sk, | |||
886 | ipv6_addr_copy(&newnp->rcv_saddr, &ireq6->loc_addr); | 880 | ipv6_addr_copy(&newnp->rcv_saddr, &ireq6->loc_addr); |
887 | newsk->sk_bound_dev_if = ireq6->iif; | 881 | newsk->sk_bound_dev_if = ireq6->iif; |
888 | 882 | ||
889 | /* Now IPv6 options... | 883 | /* Now IPv6 options... |
890 | 884 | ||
891 | First: no IPv4 options. | 885 | First: no IPv4 options. |
892 | */ | 886 | */ |
@@ -908,20 +902,20 @@ static struct sock *dccp_v6_request_recv_sock(struct sock *sk, | |||
908 | newnp->mcast_oif = inet6_iif(skb); | 902 | newnp->mcast_oif = inet6_iif(skb); |
909 | newnp->mcast_hops = skb->nh.ipv6h->hop_limit; | 903 | newnp->mcast_hops = skb->nh.ipv6h->hop_limit; |
910 | 904 | ||
911 | /* Clone native IPv6 options from listening socket (if any) | 905 | /* |
912 | 906 | * Clone native IPv6 options from listening socket (if any) | |
913 | Yes, keeping reference count would be much more clever, | 907 | * |
914 | but we make one more one thing there: reattach optmem | 908 | * Yes, keeping reference count would be much more clever, but we make |
915 | to newsk. | 909 | * one more one thing there: reattach optmem to newsk. |
916 | */ | 910 | */ |
917 | if (opt) { | 911 | if (opt != NULL) { |
918 | newnp->opt = ipv6_dup_options(newsk, opt); | 912 | newnp->opt = ipv6_dup_options(newsk, opt); |
919 | if (opt != np->opt) | 913 | if (opt != np->opt) |
920 | sock_kfree_s(sk, opt, opt->tot_len); | 914 | sock_kfree_s(sk, opt, opt->tot_len); |
921 | } | 915 | } |
922 | 916 | ||
923 | inet_csk(newsk)->icsk_ext_hdr_len = 0; | 917 | inet_csk(newsk)->icsk_ext_hdr_len = 0; |
924 | if (newnp->opt) | 918 | if (newnp->opt != NULL) |
925 | inet_csk(newsk)->icsk_ext_hdr_len = (newnp->opt->opt_nflen + | 919 | inet_csk(newsk)->icsk_ext_hdr_len = (newnp->opt->opt_nflen + |
926 | newnp->opt->opt_flen); | 920 | newnp->opt->opt_flen); |
927 | 921 | ||
@@ -938,7 +932,7 @@ out_overflow: | |||
938 | NET_INC_STATS_BH(LINUX_MIB_LISTENOVERFLOWS); | 932 | NET_INC_STATS_BH(LINUX_MIB_LISTENOVERFLOWS); |
939 | out: | 933 | out: |
940 | NET_INC_STATS_BH(LINUX_MIB_LISTENDROPS); | 934 | NET_INC_STATS_BH(LINUX_MIB_LISTENDROPS); |
941 | if (opt && opt != np->opt) | 935 | if (opt != NULL && opt != np->opt) |
942 | sock_kfree_s(sk, opt, opt->tot_len); | 936 | sock_kfree_s(sk, opt, opt->tot_len); |
943 | dst_release(dst); | 937 | dst_release(dst); |
944 | return NULL; | 938 | return NULL; |
@@ -972,8 +966,8 @@ static int dccp_v6_do_rcv(struct sock *sk, struct sk_buff *skb) | |||
972 | goto discard; | 966 | goto discard; |
973 | 967 | ||
974 | /* | 968 | /* |
975 | * socket locking is here for SMP purposes as backlog rcv | 969 | * socket locking is here for SMP purposes as backlog rcv is currently |
976 | * is currently called with bh processing disabled. | 970 | * called with bh processing disabled. |
977 | */ | 971 | */ |
978 | 972 | ||
979 | /* Do Stevens' IPV6_PKTOPTIONS. | 973 | /* Do Stevens' IPV6_PKTOPTIONS. |
@@ -998,20 +992,20 @@ static int dccp_v6_do_rcv(struct sock *sk, struct sk_buff *skb) | |||
998 | return 0; | 992 | return 0; |
999 | } | 993 | } |
1000 | 994 | ||
1001 | if (sk->sk_state == DCCP_LISTEN) { | 995 | if (sk->sk_state == DCCP_LISTEN) { |
1002 | struct sock *nsk = dccp_v6_hnd_req(sk, skb); | 996 | struct sock *nsk = dccp_v6_hnd_req(sk, skb); |
1003 | if (!nsk) | ||
1004 | goto discard; | ||
1005 | 997 | ||
998 | if (nsk == NULL) | ||
999 | goto discard; | ||
1006 | /* | 1000 | /* |
1007 | * Queue it on the new socket if the new socket is active, | 1001 | * Queue it on the new socket if the new socket is active, |
1008 | * otherwise we just shortcircuit this and continue with | 1002 | * otherwise we just shortcircuit this and continue with |
1009 | * the new socket.. | 1003 | * the new socket.. |
1010 | */ | 1004 | */ |
1011 | if(nsk != sk) { | 1005 | if (nsk != sk) { |
1012 | if (dccp_child_process(sk, nsk, skb)) | 1006 | if (dccp_child_process(sk, nsk, skb)) |
1013 | goto reset; | 1007 | goto reset; |
1014 | if (opt_skb) | 1008 | if (opt_skb != NULL) |
1015 | __kfree_skb(opt_skb); | 1009 | __kfree_skb(opt_skb); |
1016 | return 0; | 1010 | return 0; |
1017 | } | 1011 | } |
@@ -1024,7 +1018,7 @@ static int dccp_v6_do_rcv(struct sock *sk, struct sk_buff *skb) | |||
1024 | reset: | 1018 | reset: |
1025 | dccp_v6_ctl_send_reset(skb); | 1019 | dccp_v6_ctl_send_reset(skb); |
1026 | discard: | 1020 | discard: |
1027 | if (opt_skb) | 1021 | if (opt_skb != NULL) |
1028 | __kfree_skb(opt_skb); | 1022 | __kfree_skb(opt_skb); |
1029 | kfree_skb(skb); | 1023 | kfree_skb(skb); |
1030 | return 0; | 1024 | return 0; |
@@ -1057,7 +1051,7 @@ static int dccp_v6_rcv(struct sk_buff **pskb) | |||
1057 | dh->dccph_sport, | 1051 | dh->dccph_sport, |
1058 | &skb->nh.ipv6h->daddr, ntohs(dh->dccph_dport), | 1052 | &skb->nh.ipv6h->daddr, ntohs(dh->dccph_dport), |
1059 | inet6_iif(skb)); | 1053 | inet6_iif(skb)); |
1060 | /* | 1054 | /* |
1061 | * Step 2: | 1055 | * Step 2: |
1062 | * If no socket ... | 1056 | * If no socket ... |
1063 | * Generate Reset(No Connection) unless P.type == Reset | 1057 | * Generate Reset(No Connection) unless P.type == Reset |
@@ -1066,15 +1060,14 @@ static int dccp_v6_rcv(struct sk_buff **pskb) | |||
1066 | if (sk == NULL) | 1060 | if (sk == NULL) |
1067 | goto no_dccp_socket; | 1061 | goto no_dccp_socket; |
1068 | 1062 | ||
1069 | /* | 1063 | /* |
1070 | * Step 2: | 1064 | * Step 2: |
1071 | * ... or S.state == TIMEWAIT, | 1065 | * ... or S.state == TIMEWAIT, |
1072 | * Generate Reset(No Connection) unless P.type == Reset | 1066 | * Generate Reset(No Connection) unless P.type == Reset |
1073 | * Drop packet and return | 1067 | * Drop packet and return |
1074 | */ | 1068 | */ |
1075 | |||
1076 | if (sk->sk_state == DCCP_TIME_WAIT) | 1069 | if (sk->sk_state == DCCP_TIME_WAIT) |
1077 | goto do_time_wait; | 1070 | goto do_time_wait; |
1078 | 1071 | ||
1079 | if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb)) | 1072 | if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb)) |
1080 | goto discard_and_relse; | 1073 | goto discard_and_relse; |
@@ -1113,32 +1106,40 @@ do_time_wait: | |||
1113 | } | 1106 | } |
1114 | 1107 | ||
1115 | static struct inet_connection_sock_af_ops dccp_ipv6_af_ops = { | 1108 | static struct inet_connection_sock_af_ops dccp_ipv6_af_ops = { |
1116 | .queue_xmit = inet6_csk_xmit, | 1109 | .queue_xmit = inet6_csk_xmit, |
1117 | .send_check = dccp_v6_send_check, | 1110 | .send_check = dccp_v6_send_check, |
1118 | .rebuild_header = inet6_sk_rebuild_header, | 1111 | .rebuild_header = inet6_sk_rebuild_header, |
1119 | .conn_request = dccp_v6_conn_request, | 1112 | .conn_request = dccp_v6_conn_request, |
1120 | .syn_recv_sock = dccp_v6_request_recv_sock, | 1113 | .syn_recv_sock = dccp_v6_request_recv_sock, |
1121 | .net_header_len = sizeof(struct ipv6hdr), | 1114 | .net_header_len = sizeof(struct ipv6hdr), |
1122 | .setsockopt = ipv6_setsockopt, | 1115 | .setsockopt = ipv6_setsockopt, |
1123 | .getsockopt = ipv6_getsockopt, | 1116 | .getsockopt = ipv6_getsockopt, |
1124 | .addr2sockaddr = inet6_csk_addr2sockaddr, | 1117 | .addr2sockaddr = inet6_csk_addr2sockaddr, |
1125 | .sockaddr_len = sizeof(struct sockaddr_in6) | 1118 | .sockaddr_len = sizeof(struct sockaddr_in6), |
1119 | #ifdef CONFIG_COMPAT | ||
1120 | .compat_setsockopt = compat_ipv6_setsockopt, | ||
1121 | .compat_getsockopt = compat_ipv6_getsockopt, | ||
1122 | #endif | ||
1126 | }; | 1123 | }; |
1127 | 1124 | ||
1128 | /* | 1125 | /* |
1129 | * DCCP over IPv4 via INET6 API | 1126 | * DCCP over IPv4 via INET6 API |
1130 | */ | 1127 | */ |
1131 | static struct inet_connection_sock_af_ops dccp_ipv6_mapped = { | 1128 | static struct inet_connection_sock_af_ops dccp_ipv6_mapped = { |
1132 | .queue_xmit = ip_queue_xmit, | 1129 | .queue_xmit = ip_queue_xmit, |
1133 | .send_check = dccp_v4_send_check, | 1130 | .send_check = dccp_v4_send_check, |
1134 | .rebuild_header = inet_sk_rebuild_header, | 1131 | .rebuild_header = inet_sk_rebuild_header, |
1135 | .conn_request = dccp_v6_conn_request, | 1132 | .conn_request = dccp_v6_conn_request, |
1136 | .syn_recv_sock = dccp_v6_request_recv_sock, | 1133 | .syn_recv_sock = dccp_v6_request_recv_sock, |
1137 | .net_header_len = sizeof(struct iphdr), | 1134 | .net_header_len = sizeof(struct iphdr), |
1138 | .setsockopt = ipv6_setsockopt, | 1135 | .setsockopt = ipv6_setsockopt, |
1139 | .getsockopt = ipv6_getsockopt, | 1136 | .getsockopt = ipv6_getsockopt, |
1140 | .addr2sockaddr = inet6_csk_addr2sockaddr, | 1137 | .addr2sockaddr = inet6_csk_addr2sockaddr, |
1141 | .sockaddr_len = sizeof(struct sockaddr_in6) | 1138 | .sockaddr_len = sizeof(struct sockaddr_in6), |
1139 | #ifdef CONFIG_COMPAT | ||
1140 | .compat_setsockopt = compat_ipv6_setsockopt, | ||
1141 | .compat_getsockopt = compat_ipv6_getsockopt, | ||
1142 | #endif | ||
1142 | }; | 1143 | }; |
1143 | 1144 | ||
1144 | /* NOTE: A lot of things set to zero explicitly by call to | 1145 | /* NOTE: A lot of things set to zero explicitly by call to |
@@ -1146,71 +1147,83 @@ static struct inet_connection_sock_af_ops dccp_ipv6_mapped = { | |||
1146 | */ | 1147 | */ |
1147 | static int dccp_v6_init_sock(struct sock *sk) | 1148 | static int dccp_v6_init_sock(struct sock *sk) |
1148 | { | 1149 | { |
1149 | int err = dccp_v4_init_sock(sk); | 1150 | static __u8 dccp_v6_ctl_sock_initialized; |
1151 | int err = dccp_init_sock(sk, dccp_v6_ctl_sock_initialized); | ||
1150 | 1152 | ||
1151 | if (err == 0) | 1153 | if (err == 0) { |
1154 | if (unlikely(!dccp_v6_ctl_sock_initialized)) | ||
1155 | dccp_v6_ctl_sock_initialized = 1; | ||
1152 | inet_csk(sk)->icsk_af_ops = &dccp_ipv6_af_ops; | 1156 | inet_csk(sk)->icsk_af_ops = &dccp_ipv6_af_ops; |
1157 | } | ||
1153 | 1158 | ||
1154 | return err; | 1159 | return err; |
1155 | } | 1160 | } |
1156 | 1161 | ||
1157 | static int dccp_v6_destroy_sock(struct sock *sk) | 1162 | static int dccp_v6_destroy_sock(struct sock *sk) |
1158 | { | 1163 | { |
1159 | dccp_v4_destroy_sock(sk); | 1164 | dccp_destroy_sock(sk); |
1160 | return inet6_destroy_sock(sk); | 1165 | return inet6_destroy_sock(sk); |
1161 | } | 1166 | } |
1162 | 1167 | ||
1163 | static struct proto dccp_v6_prot = { | 1168 | static struct proto dccp_v6_prot = { |
1164 | .name = "DCCPv6", | 1169 | .name = "DCCPv6", |
1165 | .owner = THIS_MODULE, | 1170 | .owner = THIS_MODULE, |
1166 | .close = dccp_close, | 1171 | .close = dccp_close, |
1167 | .connect = dccp_v6_connect, | 1172 | .connect = dccp_v6_connect, |
1168 | .disconnect = dccp_disconnect, | 1173 | .disconnect = dccp_disconnect, |
1169 | .ioctl = dccp_ioctl, | 1174 | .ioctl = dccp_ioctl, |
1170 | .init = dccp_v6_init_sock, | 1175 | .init = dccp_v6_init_sock, |
1171 | .setsockopt = dccp_setsockopt, | 1176 | .setsockopt = dccp_setsockopt, |
1172 | .getsockopt = dccp_getsockopt, | 1177 | .getsockopt = dccp_getsockopt, |
1173 | .sendmsg = dccp_sendmsg, | 1178 | .sendmsg = dccp_sendmsg, |
1174 | .recvmsg = dccp_recvmsg, | 1179 | .recvmsg = dccp_recvmsg, |
1175 | .backlog_rcv = dccp_v6_do_rcv, | 1180 | .backlog_rcv = dccp_v6_do_rcv, |
1176 | .hash = dccp_v6_hash, | 1181 | .hash = dccp_v6_hash, |
1177 | .unhash = dccp_unhash, | 1182 | .unhash = dccp_unhash, |
1178 | .accept = inet_csk_accept, | 1183 | .accept = inet_csk_accept, |
1179 | .get_port = dccp_v6_get_port, | 1184 | .get_port = dccp_v6_get_port, |
1180 | .shutdown = dccp_shutdown, | 1185 | .shutdown = dccp_shutdown, |
1181 | .destroy = dccp_v6_destroy_sock, | 1186 | .destroy = dccp_v6_destroy_sock, |
1182 | .orphan_count = &dccp_orphan_count, | 1187 | .orphan_count = &dccp_orphan_count, |
1183 | .max_header = MAX_DCCP_HEADER, | 1188 | .max_header = MAX_DCCP_HEADER, |
1184 | .obj_size = sizeof(struct dccp6_sock), | 1189 | .obj_size = sizeof(struct dccp6_sock), |
1185 | .rsk_prot = &dccp6_request_sock_ops, | 1190 | .rsk_prot = &dccp6_request_sock_ops, |
1186 | .twsk_prot = &dccp6_timewait_sock_ops, | 1191 | .twsk_prot = &dccp6_timewait_sock_ops, |
1192 | #ifdef CONFIG_COMPAT | ||
1193 | .compat_setsockopt = compat_dccp_setsockopt, | ||
1194 | .compat_getsockopt = compat_dccp_getsockopt, | ||
1195 | #endif | ||
1187 | }; | 1196 | }; |
1188 | 1197 | ||
1189 | static struct inet6_protocol dccp_v6_protocol = { | 1198 | static struct inet6_protocol dccp_v6_protocol = { |
1190 | .handler = dccp_v6_rcv, | 1199 | .handler = dccp_v6_rcv, |
1191 | .err_handler = dccp_v6_err, | 1200 | .err_handler = dccp_v6_err, |
1192 | .flags = INET6_PROTO_NOPOLICY | INET6_PROTO_FINAL, | 1201 | .flags = INET6_PROTO_NOPOLICY | INET6_PROTO_FINAL, |
1193 | }; | 1202 | }; |
1194 | 1203 | ||
1195 | static struct proto_ops inet6_dccp_ops = { | 1204 | static struct proto_ops inet6_dccp_ops = { |
1196 | .family = PF_INET6, | 1205 | .family = PF_INET6, |
1197 | .owner = THIS_MODULE, | 1206 | .owner = THIS_MODULE, |
1198 | .release = inet6_release, | 1207 | .release = inet6_release, |
1199 | .bind = inet6_bind, | 1208 | .bind = inet6_bind, |
1200 | .connect = inet_stream_connect, | 1209 | .connect = inet_stream_connect, |
1201 | .socketpair = sock_no_socketpair, | 1210 | .socketpair = sock_no_socketpair, |
1202 | .accept = inet_accept, | 1211 | .accept = inet_accept, |
1203 | .getname = inet6_getname, | 1212 | .getname = inet6_getname, |
1204 | .poll = dccp_poll, | 1213 | .poll = dccp_poll, |
1205 | .ioctl = inet6_ioctl, | 1214 | .ioctl = inet6_ioctl, |
1206 | .listen = inet_dccp_listen, | 1215 | .listen = inet_dccp_listen, |
1207 | .shutdown = inet_shutdown, | 1216 | .shutdown = inet_shutdown, |
1208 | .setsockopt = sock_common_setsockopt, | 1217 | .setsockopt = sock_common_setsockopt, |
1209 | .getsockopt = sock_common_getsockopt, | 1218 | .getsockopt = sock_common_getsockopt, |
1210 | .sendmsg = inet_sendmsg, | 1219 | .sendmsg = inet_sendmsg, |
1211 | .recvmsg = sock_common_recvmsg, | 1220 | .recvmsg = sock_common_recvmsg, |
1212 | .mmap = sock_no_mmap, | 1221 | .mmap = sock_no_mmap, |
1213 | .sendpage = sock_no_sendpage, | 1222 | .sendpage = sock_no_sendpage, |
1223 | #ifdef CONFIG_COMPAT | ||
1224 | .compat_setsockopt = compat_sock_common_setsockopt, | ||
1225 | .compat_getsockopt = compat_sock_common_getsockopt, | ||
1226 | #endif | ||
1214 | }; | 1227 | }; |
1215 | 1228 | ||
1216 | static struct inet_protosw dccp_v6_protosw = { | 1229 | static struct inet_protosw dccp_v6_protosw = { |
@@ -1234,8 +1247,16 @@ static int __init dccp_v6_init(void) | |||
1234 | goto out_unregister_proto; | 1247 | goto out_unregister_proto; |
1235 | 1248 | ||
1236 | inet6_register_protosw(&dccp_v6_protosw); | 1249 | inet6_register_protosw(&dccp_v6_protosw); |
1250 | |||
1251 | err = inet_csk_ctl_sock_create(&dccp_v6_ctl_socket, PF_INET6, | ||
1252 | SOCK_DCCP, IPPROTO_DCCP); | ||
1253 | if (err != 0) | ||
1254 | goto out_unregister_protosw; | ||
1237 | out: | 1255 | out: |
1238 | return err; | 1256 | return err; |
1257 | out_unregister_protosw: | ||
1258 | inet6_del_protocol(&dccp_v6_protocol, IPPROTO_DCCP); | ||
1259 | inet6_unregister_protosw(&dccp_v6_protosw); | ||
1239 | out_unregister_proto: | 1260 | out_unregister_proto: |
1240 | proto_unregister(&dccp_v6_prot); | 1261 | proto_unregister(&dccp_v6_prot); |
1241 | goto out; | 1262 | goto out; |