tcp: constify tcp_create_openreq_child() socket argument
[deliverable/linux.git] / net / dccp / ipv6.c
CommitLineData
3df80d93
ACM
1/*
2 * DCCP over IPv6
45329e71 3 * Linux INET6 implementation
3df80d93
ACM
4 *
5 * Based on net/dccp6/ipv6.c
6 *
7 * Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * as published by the Free Software Foundation; either version
12 * 2 of the License, or (at your option) any later version.
13 */
14
3df80d93
ACM
15#include <linux/module.h>
16#include <linux/random.h>
5a0e3ad6 17#include <linux/slab.h>
3df80d93
ACM
18#include <linux/xfrm.h>
19
20#include <net/addrconf.h>
21#include <net/inet_common.h>
22#include <net/inet_hashtables.h>
14c85021 23#include <net/inet_sock.h>
3df80d93
ACM
24#include <net/inet6_connection_sock.h>
25#include <net/inet6_hashtables.h>
26#include <net/ip6_route.h>
27#include <net/ipv6.h>
28#include <net/protocol.h>
29#include <net/transp_v6.h>
aa0e4e4a 30#include <net/ip6_checksum.h>
3df80d93 31#include <net/xfrm.h>
6e5714ea 32#include <net/secure_seq.h>
3df80d93
ACM
33
34#include "dccp.h"
35#include "ipv6.h"
4b79f0af 36#include "feat.h"
3df80d93 37
13f51d82 38/* The per-net dccp.v6_ctl_sk is used for sending RSTs and ACKs */
72478873 39
3b401a81
SH
40static const struct inet_connection_sock_af_ops dccp_ipv6_mapped;
41static const struct inet_connection_sock_af_ops dccp_ipv6_af_ops;
3df80d93 42
6f4e5fff 43/* add pseudo-header to DCCP checksum stored in skb->csum */
868c86bc 44static inline __sum16 dccp_v6_csum_finish(struct sk_buff *skb,
b71d1d42
ED
45 const struct in6_addr *saddr,
46 const struct in6_addr *daddr)
3df80d93 47{
6f4e5fff
GR
48 return csum_ipv6_magic(saddr, daddr, skb->len, IPPROTO_DCCP, skb->csum);
49}
50
bb296246 51static inline void dccp_v6_send_check(struct sock *sk, struct sk_buff *skb)
6f4e5fff
GR
52{
53 struct ipv6_pinfo *np = inet6_sk(sk);
54 struct dccp_hdr *dh = dccp_hdr(skb);
55
56 dccp_csum_outgoing(skb);
efe4208f 57 dh->dccph_checksum = dccp_v6_csum_finish(skb, &np->saddr, &sk->sk_v6_daddr);
3df80d93
ACM
58}
59
6e5714ea 60static inline __u64 dccp_v6_init_sequence(struct sk_buff *skb)
d7f7365f 61{
0660e03f
ACM
62 return secure_dccpv6_sequence_number(ipv6_hdr(skb)->daddr.s6_addr32,
63 ipv6_hdr(skb)->saddr.s6_addr32,
d7f7365f
GR
64 dccp_hdr(skb)->dccph_dport,
65 dccp_hdr(skb)->dccph_sport );
66
3df80d93
ACM
67}
68
3df80d93 69static void dccp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
d5fdd6ba 70 u8 type, u8 code, int offset, __be32 info)
3df80d93 71{
b71d1d42 72 const struct ipv6hdr *hdr = (const struct ipv6hdr *)skb->data;
3df80d93 73 const struct dccp_hdr *dh = (struct dccp_hdr *)(skb->data + offset);
e0bcfb0c 74 struct dccp_sock *dp;
3df80d93
ACM
75 struct ipv6_pinfo *np;
76 struct sock *sk;
77 int err;
78 __u64 seq;
ca12a1a4 79 struct net *net = dev_net(skb->dev);
3df80d93 80
860239c5
WY
81 if (skb->len < offset + sizeof(*dh) ||
82 skb->len < offset + __dccp_basic_hdr_len(dh)) {
e41b5368
DL
83 ICMP6_INC_STATS_BH(net, __in6_dev_get(skb->dev),
84 ICMP6_MIB_INERRORS);
860239c5
WY
85 return;
86 }
87
52036a43
ED
88 sk = __inet6_lookup_established(net, &dccp_hashinfo,
89 &hdr->daddr, dh->dccph_dport,
90 &hdr->saddr, ntohs(dh->dccph_sport),
91 inet6_iif(skb));
3df80d93 92
52036a43 93 if (!sk) {
e41b5368
DL
94 ICMP6_INC_STATS_BH(net, __in6_dev_get(skb->dev),
95 ICMP6_MIB_INERRORS);
3df80d93
ACM
96 return;
97 }
98
99 if (sk->sk_state == DCCP_TIME_WAIT) {
9469c7b4 100 inet_twsk_put(inet_twsk(sk));
3df80d93
ACM
101 return;
102 }
52036a43
ED
103 seq = dccp_hdr_seq(dh);
104 if (sk->sk_state == DCCP_NEW_SYN_RECV)
105 return dccp_req_err(sk, seq);
3df80d93
ACM
106
107 bh_lock_sock(sk);
108 if (sock_owned_by_user(sk))
de0744af 109 NET_INC_STATS_BH(net, LINUX_MIB_LOCKDROPPEDICMPS);
3df80d93
ACM
110
111 if (sk->sk_state == DCCP_CLOSED)
112 goto out;
113
e0bcfb0c 114 dp = dccp_sk(sk);
e0bcfb0c
WY
115 if ((1 << sk->sk_state) & ~(DCCPF_REQUESTING | DCCPF_LISTEN) &&
116 !between48(seq, dp->dccps_awl, dp->dccps_awh)) {
117 NET_INC_STATS_BH(net, LINUX_MIB_OUTOFWINDOWICMPS);
118 goto out;
119 }
120
3df80d93
ACM
121 np = inet6_sk(sk);
122
ec18d9a2
DM
123 if (type == NDISC_REDIRECT) {
124 struct dst_entry *dst = __sk_dst_check(sk, np->dst_cookie);
125
1ed5c48f 126 if (dst)
6700c270 127 dst->ops->redirect(dst, sk, skb);
bd784a14 128 goto out;
ec18d9a2
DM
129 }
130
3df80d93 131 if (type == ICMPV6_PKT_TOOBIG) {
3df80d93
ACM
132 struct dst_entry *dst = NULL;
133
93b36cf3
HFS
134 if (!ip6_sk_accept_pmtu(sk))
135 goto out;
136
3df80d93
ACM
137 if (sock_owned_by_user(sk))
138 goto out;
139 if ((1 << sk->sk_state) & (DCCPF_LISTEN | DCCPF_CLOSED))
140 goto out;
141
35ad9b9c
DM
142 dst = inet6_csk_update_pmtu(sk, ntohl(info));
143 if (!dst)
144 goto out;
145
146 if (inet_csk(sk)->icsk_pmtu_cookie > dst_mtu(dst))
3df80d93 147 dccp_sync_mss(sk, dst_mtu(dst));
3df80d93
ACM
148 goto out;
149 }
150
151 icmpv6_err_convert(type, code, &err);
152
3df80d93
ACM
153 /* Might be for an request_sock */
154 switch (sk->sk_state) {
3df80d93
ACM
155 case DCCP_REQUESTING:
156 case DCCP_RESPOND: /* Cannot happen.
45329e71 157 It can, it SYNs are crossed. --ANK */
3df80d93
ACM
158 if (!sock_owned_by_user(sk)) {
159 DCCP_INC_STATS_BH(DCCP_MIB_ATTEMPTFAILS);
160 sk->sk_err = err;
161 /*
162 * Wake people up to see the error
163 * (see connect in sock.c)
164 */
165 sk->sk_error_report(sk);
3df80d93
ACM
166 dccp_done(sk);
167 } else
168 sk->sk_err_soft = err;
169 goto out;
170 }
171
172 if (!sock_owned_by_user(sk) && np->recverr) {
173 sk->sk_err = err;
174 sk->sk_error_report(sk);
175 } else
176 sk->sk_err_soft = err;
177
178out:
179 bh_unlock_sock(sk);
180 sock_put(sk);
181}
182
183
ea3bea3a 184static int dccp_v6_send_response(const struct sock *sk, struct request_sock *req)
3df80d93 185{
634fb979 186 struct inet_request_sock *ireq = inet_rsk(req);
3df80d93
ACM
187 struct ipv6_pinfo *np = inet6_sk(sk);
188 struct sk_buff *skb;
20c59de2 189 struct in6_addr *final_p, final;
4c9483b2 190 struct flowi6 fl6;
3df80d93 191 int err = -1;
fd80eb94 192 struct dst_entry *dst;
3df80d93 193
4c9483b2
DM
194 memset(&fl6, 0, sizeof(fl6));
195 fl6.flowi6_proto = IPPROTO_DCCP;
634fb979
ED
196 fl6.daddr = ireq->ir_v6_rmt_addr;
197 fl6.saddr = ireq->ir_v6_loc_addr;
4c9483b2 198 fl6.flowlabel = 0;
634fb979
ED
199 fl6.flowi6_oif = ireq->ir_iif;
200 fl6.fl6_dport = ireq->ir_rmt_port;
b44084c2 201 fl6.fl6_sport = htons(ireq->ir_num);
4c9483b2 202 security_req_classify_flow(req, flowi6_to_flowi(&fl6));
3df80d93 203
3df80d93 204
0979e465 205 final_p = fl6_update_dst(&fl6, np->opt, &final);
3df80d93 206
0e0d44ab 207 dst = ip6_dst_lookup_flow(sk, &fl6, final_p);
68d0c6d3
DM
208 if (IS_ERR(dst)) {
209 err = PTR_ERR(dst);
210 dst = NULL;
fd80eb94 211 goto done;
68d0c6d3 212 }
3df80d93
ACM
213
214 skb = dccp_make_response(sk, dst, req);
215 if (skb != NULL) {
216 struct dccp_hdr *dh = dccp_hdr(skb);
45329e71 217
6f4e5fff 218 dh->dccph_checksum = dccp_v6_csum_finish(skb,
634fb979
ED
219 &ireq->ir_v6_loc_addr,
220 &ireq->ir_v6_rmt_addr);
221 fl6.daddr = ireq->ir_v6_rmt_addr;
0979e465 222 err = ip6_xmit(sk, skb, &fl6, np->opt, np->tclass);
b9df3cb8 223 err = net_xmit_eval(err);
3df80d93
ACM
224 }
225
226done:
0cbd7825 227 dst_release(dst);
3df80d93
ACM
228 return err;
229}
230
231static void dccp_v6_reqsk_destructor(struct request_sock *req)
232{
d99a7bd2 233 dccp_feat_list_purge(&dccp_rsk(req)->dreq_featneg);
634fb979 234 kfree_skb(inet_rsk(req)->pktopts);
3df80d93
ACM
235}
236
a00e7444 237static void dccp_v6_ctl_send_reset(const struct sock *sk, struct sk_buff *rxskb)
3df80d93 238{
b71d1d42 239 const struct ipv6hdr *rxip6h;
3df80d93 240 struct sk_buff *skb;
4c9483b2 241 struct flowi6 fl6;
adf30907 242 struct net *net = dev_net(skb_dst(rxskb)->dev);
334527d3 243 struct sock *ctl_sk = net->dccp.v6_ctl_sk;
adf30907 244 struct dst_entry *dst;
3df80d93 245
e356d37a 246 if (dccp_hdr(rxskb)->dccph_type == DCCP_PKT_RESET)
3df80d93
ACM
247 return;
248
249 if (!ipv6_unicast_destination(rxskb))
45329e71 250 return;
3df80d93 251
02047741 252 skb = dccp_ctl_make_reset(ctl_sk, rxskb);
45329e71 253 if (skb == NULL)
8109b02b 254 return;
3df80d93 255
0660e03f 256 rxip6h = ipv6_hdr(rxskb);
e356d37a
GR
257 dccp_hdr(skb)->dccph_checksum = dccp_v6_csum_finish(skb, &rxip6h->saddr,
258 &rxip6h->daddr);
6f4e5fff 259
4c9483b2 260 memset(&fl6, 0, sizeof(fl6));
4e3fd7a0
AD
261 fl6.daddr = rxip6h->saddr;
262 fl6.saddr = rxip6h->daddr;
6f4e5fff 263
4c9483b2
DM
264 fl6.flowi6_proto = IPPROTO_DCCP;
265 fl6.flowi6_oif = inet6_iif(rxskb);
1958b856
DM
266 fl6.fl6_dport = dccp_hdr(skb)->dccph_dport;
267 fl6.fl6_sport = dccp_hdr(skb)->dccph_sport;
4c9483b2 268 security_skb_classify_flow(rxskb, flowi6_to_flowi(&fl6));
3df80d93
ACM
269
270 /* sk = NULL, but it is safe for now. RST socket required. */
0e0d44ab 271 dst = ip6_dst_lookup_flow(ctl_sk, &fl6, NULL);
68d0c6d3
DM
272 if (!IS_ERR(dst)) {
273 skb_dst_set(skb, dst);
b903d324 274 ip6_xmit(ctl_sk, skb, &fl6, NULL, 0);
68d0c6d3
DM
275 DCCP_INC_STATS_BH(DCCP_MIB_OUTSEGS);
276 DCCP_INC_STATS_BH(DCCP_MIB_OUTRSTS);
277 return;
3df80d93
ACM
278 }
279
280 kfree_skb(skb);
281}
282
73c9e02c
GR
283static struct request_sock_ops dccp6_request_sock_ops = {
284 .family = AF_INET6,
285 .obj_size = sizeof(struct dccp6_request_sock),
286 .rtx_syn_ack = dccp_v6_send_response,
287 .send_ack = dccp_reqsk_send_ack,
288 .destructor = dccp_v6_reqsk_destructor,
289 .send_reset = dccp_v6_ctl_send_reset,
c72e1183 290 .syn_ack_timeout = dccp_syn_ack_timeout,
73c9e02c
GR
291};
292
3df80d93
ACM
293static struct sock *dccp_v6_hnd_req(struct sock *sk,struct sk_buff *skb)
294{
295 const struct dccp_hdr *dh = dccp_hdr(skb);
0660e03f 296 const struct ipv6hdr *iph = ipv6_hdr(skb);
52452c54 297 struct request_sock *req;
3df80d93 298 struct sock *nsk;
52452c54
ED
299
300 req = inet6_csk_search_req(sk, dh->dccph_sport, &iph->saddr,
301 &iph->daddr, inet6_iif(skb));
fa76ce73
ED
302 if (req) {
303 nsk = dccp_check_req(sk, skb, req);
b357a364
ED
304 if (!nsk)
305 reqsk_put(req);
fa76ce73
ED
306 return nsk;
307 }
671a1c74 308 nsk = __inet6_lookup_established(sock_net(sk), &dccp_hashinfo,
3df80d93
ACM
309 &iph->saddr, dh->dccph_sport,
310 &iph->daddr, ntohs(dh->dccph_dport),
311 inet6_iif(skb));
3df80d93
ACM
312 if (nsk != NULL) {
313 if (nsk->sk_state != DCCP_TIME_WAIT) {
314 bh_lock_sock(nsk);
315 return nsk;
316 }
9469c7b4 317 inet_twsk_put(inet_twsk(nsk));
3df80d93
ACM
318 return NULL;
319 }
320
321 return sk;
322}
323
324static int dccp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
325{
3df80d93
ACM
326 struct request_sock *req;
327 struct dccp_request_sock *dreq;
634fb979 328 struct inet_request_sock *ireq;
3df80d93 329 struct ipv6_pinfo *np = inet6_sk(sk);
8109b02b 330 const __be32 service = dccp_hdr_request(skb)->dccph_req_service;
3df80d93 331 struct dccp_skb_cb *dcb = DCCP_SKB_CB(skb);
3df80d93
ACM
332
333 if (skb->protocol == htons(ETH_P_IP))
334 return dccp_v4_conn_request(sk, skb);
335
336 if (!ipv6_unicast_destination(skb))
4a5409a5 337 return 0; /* discard, don't send a reset here */
3df80d93
ACM
338
339 if (dccp_bad_service_code(sk, service)) {
4a5409a5 340 dcb->dccpd_reset_code = DCCP_RESET_CODE_BAD_SERVICE_CODE;
3df80d93 341 goto drop;
8109b02b 342 }
3df80d93 343 /*
45329e71 344 * There are no SYN attacks on IPv6, yet...
3df80d93 345 */
4a5409a5 346 dcb->dccpd_reset_code = DCCP_RESET_CODE_TOO_BUSY;
3df80d93 347 if (inet_csk_reqsk_queue_is_full(sk))
45329e71 348 goto drop;
3df80d93
ACM
349
350 if (sk_acceptq_is_full(sk) && inet_csk_reqsk_queue_young(sk) > 1)
351 goto drop;
352
407640de 353 req = inet_reqsk_alloc(&dccp6_request_sock_ops, sk);
3df80d93
ACM
354 if (req == NULL)
355 goto drop;
356
ac75773c
GR
357 if (dccp_reqsk_init(req, dccp_sk(sk), skb))
358 goto drop_and_free;
3df80d93 359
8b819412
GR
360 dreq = dccp_rsk(req);
361 if (dccp_parse_options(sk, dreq, skb))
362 goto drop_and_free;
363
4237c75c
VY
364 if (security_inet_conn_request(sk, skb, req))
365 goto drop_and_free;
366
634fb979
ED
367 ireq = inet_rsk(req);
368 ireq->ir_v6_rmt_addr = ipv6_hdr(skb)->saddr;
369 ireq->ir_v6_loc_addr = ipv6_hdr(skb)->daddr;
3f66b083 370 ireq->ireq_family = AF_INET6;
3df80d93 371
a224772d 372 if (ipv6_opt_accepted(sk, skb, IP6CB(skb)) ||
3df80d93
ACM
373 np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo ||
374 np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim) {
375 atomic_inc(&skb->users);
634fb979 376 ireq->pktopts = skb;
3df80d93 377 }
634fb979 378 ireq->ir_iif = sk->sk_bound_dev_if;
3df80d93
ACM
379
380 /* So that link locals have meaning */
381 if (!sk->sk_bound_dev_if &&
634fb979
ED
382 ipv6_addr_type(&ireq->ir_v6_rmt_addr) & IPV6_ADDR_LINKLOCAL)
383 ireq->ir_iif = inet6_iif(skb);
3df80d93 384
45329e71 385 /*
3df80d93
ACM
386 * Step 3: Process LISTEN state
387 *
d83ca5ac 388 * Set S.ISR, S.GSR, S.SWL, S.SWH from packet or Init Cookie
3df80d93 389 *
f541fb7e 390 * Setting S.SWL/S.SWH to is deferred to dccp_create_openreq_child().
3df80d93 391 */
3df80d93 392 dreq->dreq_isr = dcb->dccpd_seq;
f541fb7e 393 dreq->dreq_gsr = dreq->dreq_isr;
865e9022 394 dreq->dreq_iss = dccp_v6_init_sequence(skb);
f541fb7e 395 dreq->dreq_gss = dreq->dreq_iss;
3df80d93
ACM
396 dreq->dreq_service = service;
397
1a2c6181 398 if (dccp_v6_send_response(sk, req))
3df80d93
ACM
399 goto drop_and_free;
400
401 inet6_csk_reqsk_queue_hash_add(sk, req, DCCP_TIMEOUT_INIT);
402 return 0;
403
404drop_and_free:
405 reqsk_free(req);
406drop:
407 DCCP_INC_STATS_BH(DCCP_MIB_ATTEMPTFAILS);
3df80d93
ACM
408 return -1;
409}
410
411static struct sock *dccp_v6_request_recv_sock(struct sock *sk,
412 struct sk_buff *skb,
413 struct request_sock *req,
414 struct dst_entry *dst)
415{
634fb979 416 struct inet_request_sock *ireq = inet_rsk(req);
3df80d93
ACM
417 struct ipv6_pinfo *newnp, *np = inet6_sk(sk);
418 struct inet_sock *newinet;
3df80d93
ACM
419 struct dccp6_sock *newdp6;
420 struct sock *newsk;
3df80d93
ACM
421
422 if (skb->protocol == htons(ETH_P_IP)) {
423 /*
424 * v6 mapped
425 */
3df80d93 426 newsk = dccp_v4_request_recv_sock(sk, skb, req, dst);
45329e71 427 if (newsk == NULL)
3df80d93
ACM
428 return NULL;
429
430 newdp6 = (struct dccp6_sock *)newsk;
3df80d93
ACM
431 newinet = inet_sk(newsk);
432 newinet->pinet6 = &newdp6->inet6;
433 newnp = inet6_sk(newsk);
434
435 memcpy(newnp, np, sizeof(struct ipv6_pinfo));
436
d1e559d0 437 newnp->saddr = newsk->sk_v6_rcv_saddr;
3df80d93
ACM
438
439 inet_csk(newsk)->icsk_af_ops = &dccp_ipv6_mapped;
440 newsk->sk_backlog_rcv = dccp_v4_do_rcv;
441 newnp->pktoptions = NULL;
442 newnp->opt = NULL;
443 newnp->mcast_oif = inet6_iif(skb);
0660e03f 444 newnp->mcast_hops = ipv6_hdr(skb)->hop_limit;
3df80d93
ACM
445
446 /*
447 * No need to charge this sock to the relevant IPv6 refcnt debug socks count
448 * here, dccp_create_openreq_child now does this for us, see the comment in
449 * that function for the gory details. -acme
450 */
451
452 /* It is tricky place. Until this moment IPv4 tcp
453 worked with IPv6 icsk.icsk_af_ops.
454 Sync it now.
455 */
d83d8461 456 dccp_sync_mss(newsk, inet_csk(newsk)->icsk_pmtu_cookie);
3df80d93
ACM
457
458 return newsk;
459 }
460
3df80d93
ACM
461
462 if (sk_acceptq_is_full(sk))
463 goto out_overflow;
464
f76b33c3 465 if (!dst) {
4c9483b2
DM
466 struct flowi6 fl6;
467
f76b33c3
ED
468 dst = inet6_csk_route_req(sk, &fl6, req, IPPROTO_DCCP);
469 if (!dst)
3df80d93 470 goto out;
45329e71 471 }
3df80d93
ACM
472
473 newsk = dccp_create_openreq_child(sk, req, skb);
474 if (newsk == NULL)
093d2823 475 goto out_nonewsk;
3df80d93
ACM
476
477 /*
478 * No need to charge this sock to the relevant IPv6 refcnt debug socks
479 * count here, dccp_create_openreq_child now does this for us, see the
480 * comment in that function for the gory details. -acme
481 */
482
8e1ef0a9 483 __ip6_dst_store(newsk, dst, NULL, NULL);
45329e71
ACM
484 newsk->sk_route_caps = dst->dev->features & ~(NETIF_F_IP_CSUM |
485 NETIF_F_TSO);
3df80d93
ACM
486 newdp6 = (struct dccp6_sock *)newsk;
487 newinet = inet_sk(newsk);
488 newinet->pinet6 = &newdp6->inet6;
3df80d93
ACM
489 newnp = inet6_sk(newsk);
490
491 memcpy(newnp, np, sizeof(struct ipv6_pinfo));
492
634fb979
ED
493 newsk->sk_v6_daddr = ireq->ir_v6_rmt_addr;
494 newnp->saddr = ireq->ir_v6_loc_addr;
495 newsk->sk_v6_rcv_saddr = ireq->ir_v6_loc_addr;
496 newsk->sk_bound_dev_if = ireq->ir_iif;
3df80d93 497
45329e71 498 /* Now IPv6 options...
3df80d93
ACM
499
500 First: no IPv4 options.
501 */
f6d8bd05 502 newinet->inet_opt = NULL;
3df80d93
ACM
503
504 /* Clone RX bits */
505 newnp->rxopt.all = np->rxopt.all;
506
507 /* Clone pktoptions received with SYN */
508 newnp->pktoptions = NULL;
634fb979
ED
509 if (ireq->pktopts != NULL) {
510 newnp->pktoptions = skb_clone(ireq->pktopts, GFP_ATOMIC);
511 consume_skb(ireq->pktopts);
512 ireq->pktopts = NULL;
3df80d93
ACM
513 if (newnp->pktoptions)
514 skb_set_owner_r(newnp->pktoptions, newsk);
515 }
516 newnp->opt = NULL;
517 newnp->mcast_oif = inet6_iif(skb);
0660e03f 518 newnp->mcast_hops = ipv6_hdr(skb)->hop_limit;
3df80d93 519
45329e71
ACM
520 /*
521 * Clone native IPv6 options from listening socket (if any)
522 *
523 * Yes, keeping reference count would be much more clever, but we make
524 * one more one thing there: reattach optmem to newsk.
3df80d93 525 */
0979e465
RL
526 if (np->opt != NULL)
527 newnp->opt = ipv6_dup_options(newsk, np->opt);
3df80d93 528
d83d8461 529 inet_csk(newsk)->icsk_ext_hdr_len = 0;
45329e71 530 if (newnp->opt != NULL)
d83d8461
ACM
531 inet_csk(newsk)->icsk_ext_hdr_len = (newnp->opt->opt_nflen +
532 newnp->opt->opt_flen);
3df80d93
ACM
533
534 dccp_sync_mss(newsk, dst_mtu(dst));
535
c720c7e8
ED
536 newinet->inet_daddr = newinet->inet_saddr = LOOPBACK4_IPV6;
537 newinet->inet_rcv_saddr = LOOPBACK4_IPV6;
3df80d93 538
093d2823 539 if (__inet_inherit_port(sk, newsk) < 0) {
e337e24d
CP
540 inet_csk_prepare_forced_close(newsk);
541 dccp_done(newsk);
093d2823
BS
542 goto out;
543 }
77a6a471 544 __inet_hash(newsk, NULL);
3df80d93
ACM
545
546 return newsk;
547
548out_overflow:
de0744af 549 NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENOVERFLOWS);
093d2823
BS
550out_nonewsk:
551 dst_release(dst);
3df80d93 552out:
de0744af 553 NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENDROPS);
3df80d93
ACM
554 return NULL;
555}
556
557/* The socket must have it's spinlock held when we get
558 * here.
559 *
560 * We have a potential double-lock case here, so even when
561 * doing backlog processing we use the BH locking scheme.
562 * This is because we cannot sleep with the original spinlock
563 * held.
564 */
565static int dccp_v6_do_rcv(struct sock *sk, struct sk_buff *skb)
566{
567 struct ipv6_pinfo *np = inet6_sk(sk);
568 struct sk_buff *opt_skb = NULL;
569
570 /* Imagine: socket is IPv6. IPv4 packet arrives,
571 goes to IPv4 receive handler and backlogged.
572 From backlog it always goes here. Kerboom...
573 Fortunately, dccp_rcv_established and rcv_established
574 handle them correctly, but it is not case with
575 dccp_v6_hnd_req and dccp_v6_ctl_send_reset(). --ANK
576 */
577
578 if (skb->protocol == htons(ETH_P_IP))
579 return dccp_v4_do_rcv(sk, skb);
580
fda9ef5d 581 if (sk_filter(sk, skb))
3df80d93
ACM
582 goto discard;
583
584 /*
45329e71
ACM
585 * socket locking is here for SMP purposes as backlog rcv is currently
586 * called with bh processing disabled.
3df80d93
ACM
587 */
588
589 /* Do Stevens' IPV6_PKTOPTIONS.
590
591 Yes, guys, it is the only place in our code, where we
592 may make it not affecting IPv4.
593 The rest of code is protocol independent,
594 and I do not like idea to uglify IPv4.
595
596 Actually, all the idea behind IPV6_PKTOPTIONS
597 looks not very well thought. For now we latch
598 options, received in the last packet, enqueued
599 by tcp. Feel free to propose better solution.
c9eaf173 600 --ANK (980728)
3df80d93
ACM
601 */
602 if (np->rxopt.all)
89e7e577
GR
603 /*
604 * FIXME: Add handling of IPV6_PKTOPTIONS skb. See the comments below
605 * (wrt ipv6_pktopions) and net/ipv6/tcp_ipv6.c for an example.
606 */
3df80d93
ACM
607 opt_skb = skb_clone(skb, GFP_ATOMIC);
608
609 if (sk->sk_state == DCCP_OPEN) { /* Fast path */
610 if (dccp_rcv_established(sk, skb, dccp_hdr(skb), skb->len))
611 goto reset;
fd169f15 612 if (opt_skb) {
89e7e577 613 /* XXX This is where we would goto ipv6_pktoptions. */
fd169f15
DM
614 __kfree_skb(opt_skb);
615 }
3df80d93
ACM
616 return 0;
617 }
618
d83ca5ac
GR
619 /*
620 * Step 3: Process LISTEN state
621 * If S.state == LISTEN,
622 * If P.type == Request or P contains a valid Init Cookie option,
623 * (* Must scan the packet's options to check for Init
624 * Cookies. Only Init Cookies are processed here,
625 * however; other options are processed in Step 8. This
626 * scan need only be performed if the endpoint uses Init
627 * Cookies *)
628 * (* Generate a new socket and switch to that socket *)
629 * Set S := new socket for this port pair
630 * S.state = RESPOND
631 * Choose S.ISS (initial seqno) or set from Init Cookies
632 * Initialize S.GAR := S.ISS
633 * Set S.ISR, S.GSR, S.SWL, S.SWH from packet or Init Cookies
634 * Continue with S.state == RESPOND
635 * (* A Response packet will be generated in Step 11 *)
636 * Otherwise,
637 * Generate Reset(No Connection) unless P.type == Reset
638 * Drop packet and return
639 *
640 * NOTE: the check for the packet types is done in
641 * dccp_rcv_state_process
642 */
45329e71 643 if (sk->sk_state == DCCP_LISTEN) {
3df80d93 644 struct sock *nsk = dccp_v6_hnd_req(sk, skb);
3df80d93 645
45329e71
ACM
646 if (nsk == NULL)
647 goto discard;
3df80d93
ACM
648 /*
649 * Queue it on the new socket if the new socket is active,
650 * otherwise we just shortcircuit this and continue with
651 * the new socket..
652 */
8109b02b 653 if (nsk != sk) {
3df80d93
ACM
654 if (dccp_child_process(sk, nsk, skb))
655 goto reset;
45329e71 656 if (opt_skb != NULL)
3df80d93
ACM
657 __kfree_skb(opt_skb);
658 return 0;
659 }
660 }
661
662 if (dccp_rcv_state_process(sk, skb, dccp_hdr(skb), skb->len))
663 goto reset;
fd169f15 664 if (opt_skb) {
89e7e577 665 /* XXX This is where we would goto ipv6_pktoptions. */
fd169f15
DM
666 __kfree_skb(opt_skb);
667 }
3df80d93
ACM
668 return 0;
669
670reset:
cfb6eeb4 671 dccp_v6_ctl_send_reset(sk, skb);
3df80d93 672discard:
45329e71 673 if (opt_skb != NULL)
3df80d93
ACM
674 __kfree_skb(opt_skb);
675 kfree_skb(skb);
676 return 0;
677}
678
e5bbef20 679static int dccp_v6_rcv(struct sk_buff *skb)
3df80d93
ACM
680{
681 const struct dccp_hdr *dh;
3df80d93 682 struct sock *sk;
6f4e5fff 683 int min_cov;
3df80d93 684
6f4e5fff 685 /* Step 1: Check header basics */
3df80d93
ACM
686
687 if (dccp_invalid_packet(skb))
688 goto discard_it;
689
6f4e5fff 690 /* Step 1: If header checksum is incorrect, drop packet and return. */
0660e03f
ACM
691 if (dccp_v6_csum_finish(skb, &ipv6_hdr(skb)->saddr,
692 &ipv6_hdr(skb)->daddr)) {
59348b19 693 DCCP_WARN("dropped packet with invalid checksum\n");
6f4e5fff
GR
694 goto discard_it;
695 }
696
3df80d93
ACM
697 dh = dccp_hdr(skb);
698
fde20105 699 DCCP_SKB_CB(skb)->dccpd_seq = dccp_hdr_seq(dh);
3df80d93
ACM
700 DCCP_SKB_CB(skb)->dccpd_type = dh->dccph_type;
701
702 if (dccp_packet_without_ack(skb))
703 DCCP_SKB_CB(skb)->dccpd_ack_seq = DCCP_PKT_WITHOUT_ACK_SEQ;
704 else
705 DCCP_SKB_CB(skb)->dccpd_ack_seq = dccp_hdr_ack_seq(skb);
706
707 /* Step 2:
8109b02b 708 * Look up flow ID in table and get corresponding socket */
9a1f27c4 709 sk = __inet6_lookup_skb(&dccp_hashinfo, skb,
870c3151
ED
710 dh->dccph_sport, dh->dccph_dport,
711 inet6_iif(skb));
45329e71 712 /*
3df80d93 713 * Step 2:
8109b02b 714 * If no socket ...
3df80d93 715 */
d23c7107
GR
716 if (sk == NULL) {
717 dccp_pr_debug("failed to look up flow ID in table and "
718 "get corresponding socket\n");
3df80d93 719 goto no_dccp_socket;
d23c7107 720 }
3df80d93 721
45329e71 722 /*
3df80d93 723 * Step 2:
8109b02b 724 * ... or S.state == TIMEWAIT,
3df80d93
ACM
725 * Generate Reset(No Connection) unless P.type == Reset
726 * Drop packet and return
727 */
d23c7107
GR
728 if (sk->sk_state == DCCP_TIME_WAIT) {
729 dccp_pr_debug("sk->sk_state == DCCP_TIME_WAIT: do_time_wait\n");
730 inet_twsk_put(inet_twsk(sk));
731 goto no_dccp_socket;
732 }
3df80d93 733
6f4e5fff
GR
734 /*
735 * RFC 4340, sec. 9.2.1: Minimum Checksum Coverage
8109b02b
ACM
736 * o if MinCsCov = 0, only packets with CsCov = 0 are accepted
737 * o if MinCsCov > 0, also accept packets with CsCov >= MinCsCov
6f4e5fff
GR
738 */
739 min_cov = dccp_sk(sk)->dccps_pcrlen;
740 if (dh->dccph_cscov && (min_cov == 0 || dh->dccph_cscov < min_cov)) {
741 dccp_pr_debug("Packet CsCov %d does not satisfy MinCsCov %d\n",
742 dh->dccph_cscov, min_cov);
743 /* FIXME: send Data Dropped option (see also dccp_v4_rcv) */
744 goto discard_and_relse;
745 }
746
3df80d93
ACM
747 if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb))
748 goto discard_and_relse;
749
58a5a7b9 750 return sk_receive_skb(sk, skb, 1) ? -1 : 0;
3df80d93
ACM
751
752no_dccp_socket:
753 if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb))
754 goto discard_it;
755 /*
756 * Step 2:
8109b02b 757 * If no socket ...
3df80d93
ACM
758 * Generate Reset(No Connection) unless P.type == Reset
759 * Drop packet and return
760 */
761 if (dh->dccph_type != DCCP_PKT_RESET) {
762 DCCP_SKB_CB(skb)->dccpd_reset_code =
763 DCCP_RESET_CODE_NO_CONNECTION;
cfb6eeb4 764 dccp_v6_ctl_send_reset(sk, skb);
3df80d93 765 }
3df80d93 766
d23c7107 767discard_it:
3df80d93
ACM
768 kfree_skb(skb);
769 return 0;
770
771discard_and_relse:
772 sock_put(sk);
773 goto discard_it;
3df80d93
ACM
774}
775
73c9e02c
GR
776static int dccp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
777 int addr_len)
778{
779 struct sockaddr_in6 *usin = (struct sockaddr_in6 *)uaddr;
780 struct inet_connection_sock *icsk = inet_csk(sk);
781 struct inet_sock *inet = inet_sk(sk);
782 struct ipv6_pinfo *np = inet6_sk(sk);
783 struct dccp_sock *dp = dccp_sk(sk);
20c59de2 784 struct in6_addr *saddr = NULL, *final_p, final;
4c9483b2 785 struct flowi6 fl6;
73c9e02c
GR
786 struct dst_entry *dst;
787 int addr_type;
788 int err;
789
790 dp->dccps_role = DCCP_ROLE_CLIENT;
791
792 if (addr_len < SIN6_LEN_RFC2133)
793 return -EINVAL;
794
795 if (usin->sin6_family != AF_INET6)
796 return -EAFNOSUPPORT;
797
4c9483b2 798 memset(&fl6, 0, sizeof(fl6));
73c9e02c
GR
799
800 if (np->sndflow) {
4c9483b2
DM
801 fl6.flowlabel = usin->sin6_flowinfo & IPV6_FLOWINFO_MASK;
802 IP6_ECN_flow_init(fl6.flowlabel);
803 if (fl6.flowlabel & IPV6_FLOWLABEL_MASK) {
73c9e02c 804 struct ip6_flowlabel *flowlabel;
4c9483b2 805 flowlabel = fl6_sock_lookup(sk, fl6.flowlabel);
73c9e02c
GR
806 if (flowlabel == NULL)
807 return -EINVAL;
73c9e02c
GR
808 fl6_sock_release(flowlabel);
809 }
810 }
811 /*
812 * connect() to INADDR_ANY means loopback (BSD'ism).
813 */
814 if (ipv6_addr_any(&usin->sin6_addr))
815 usin->sin6_addr.s6_addr[15] = 1;
816
817 addr_type = ipv6_addr_type(&usin->sin6_addr);
818
819 if (addr_type & IPV6_ADDR_MULTICAST)
820 return -ENETUNREACH;
821
822 if (addr_type & IPV6_ADDR_LINKLOCAL) {
823 if (addr_len >= sizeof(struct sockaddr_in6) &&
824 usin->sin6_scope_id) {
825 /* If interface is set while binding, indices
826 * must coincide.
827 */
828 if (sk->sk_bound_dev_if &&
829 sk->sk_bound_dev_if != usin->sin6_scope_id)
830 return -EINVAL;
831
832 sk->sk_bound_dev_if = usin->sin6_scope_id;
833 }
834
835 /* Connect to link-local address requires an interface */
836 if (!sk->sk_bound_dev_if)
837 return -EINVAL;
838 }
839
efe4208f 840 sk->sk_v6_daddr = usin->sin6_addr;
4c9483b2 841 np->flow_label = fl6.flowlabel;
73c9e02c
GR
842
843 /*
844 * DCCP over IPv4
845 */
846 if (addr_type == IPV6_ADDR_MAPPED) {
847 u32 exthdrlen = icsk->icsk_ext_hdr_len;
848 struct sockaddr_in sin;
849
850 SOCK_DEBUG(sk, "connect: ipv4 mapped\n");
851
852 if (__ipv6_only_sock(sk))
853 return -ENETUNREACH;
854
855 sin.sin_family = AF_INET;
856 sin.sin_port = usin->sin6_port;
857 sin.sin_addr.s_addr = usin->sin6_addr.s6_addr32[3];
858
859 icsk->icsk_af_ops = &dccp_ipv6_mapped;
860 sk->sk_backlog_rcv = dccp_v4_do_rcv;
861
862 err = dccp_v4_connect(sk, (struct sockaddr *)&sin, sizeof(sin));
863 if (err) {
864 icsk->icsk_ext_hdr_len = exthdrlen;
865 icsk->icsk_af_ops = &dccp_ipv6_af_ops;
866 sk->sk_backlog_rcv = dccp_v6_do_rcv;
867 goto failure;
73c9e02c 868 }
d1e559d0 869 np->saddr = sk->sk_v6_rcv_saddr;
73c9e02c
GR
870 return err;
871 }
872
efe4208f
ED
873 if (!ipv6_addr_any(&sk->sk_v6_rcv_saddr))
874 saddr = &sk->sk_v6_rcv_saddr;
73c9e02c 875
4c9483b2 876 fl6.flowi6_proto = IPPROTO_DCCP;
efe4208f 877 fl6.daddr = sk->sk_v6_daddr;
4e3fd7a0 878 fl6.saddr = saddr ? *saddr : np->saddr;
4c9483b2 879 fl6.flowi6_oif = sk->sk_bound_dev_if;
1958b856
DM
880 fl6.fl6_dport = usin->sin6_port;
881 fl6.fl6_sport = inet->inet_sport;
4c9483b2 882 security_sk_classify_flow(sk, flowi6_to_flowi(&fl6));
73c9e02c 883
4c9483b2 884 final_p = fl6_update_dst(&fl6, np->opt, &final);
73c9e02c 885
0e0d44ab 886 dst = ip6_dst_lookup_flow(sk, &fl6, final_p);
68d0c6d3
DM
887 if (IS_ERR(dst)) {
888 err = PTR_ERR(dst);
73c9e02c 889 goto failure;
14e50e57 890 }
73c9e02c
GR
891
892 if (saddr == NULL) {
4c9483b2 893 saddr = &fl6.saddr;
efe4208f 894 sk->sk_v6_rcv_saddr = *saddr;
73c9e02c
GR
895 }
896
897 /* set the source address */
4e3fd7a0 898 np->saddr = *saddr;
c720c7e8 899 inet->inet_rcv_saddr = LOOPBACK4_IPV6;
73c9e02c
GR
900
901 __ip6_dst_store(sk, dst, NULL, NULL);
902
903 icsk->icsk_ext_hdr_len = 0;
904 if (np->opt != NULL)
905 icsk->icsk_ext_hdr_len = (np->opt->opt_flen +
906 np->opt->opt_nflen);
907
c720c7e8 908 inet->inet_dport = usin->sin6_port;
73c9e02c
GR
909
910 dccp_set_state(sk, DCCP_REQUESTING);
911 err = inet6_hash_connect(&dccp_death_row, sk);
912 if (err)
913 goto late_failure;
d7f7365f
GR
914
915 dp->dccps_iss = secure_dccpv6_sequence_number(np->saddr.s6_addr32,
efe4208f 916 sk->sk_v6_daddr.s6_addr32,
c720c7e8
ED
917 inet->inet_sport,
918 inet->inet_dport);
73c9e02c
GR
919 err = dccp_connect(sk);
920 if (err)
921 goto late_failure;
922
923 return 0;
924
925late_failure:
926 dccp_set_state(sk, DCCP_CLOSED);
927 __sk_dst_reset(sk);
928failure:
c720c7e8 929 inet->inet_dport = 0;
73c9e02c
GR
930 sk->sk_route_caps = 0;
931 return err;
932}
933
3b401a81 934static const struct inet_connection_sock_af_ops dccp_ipv6_af_ops = {
543d9cfe
ACM
935 .queue_xmit = inet6_csk_xmit,
936 .send_check = dccp_v6_send_check,
937 .rebuild_header = inet6_sk_rebuild_header,
938 .conn_request = dccp_v6_conn_request,
939 .syn_recv_sock = dccp_v6_request_recv_sock,
940 .net_header_len = sizeof(struct ipv6hdr),
941 .setsockopt = ipv6_setsockopt,
942 .getsockopt = ipv6_getsockopt,
943 .addr2sockaddr = inet6_csk_addr2sockaddr,
944 .sockaddr_len = sizeof(struct sockaddr_in6),
ab1e0a13 945 .bind_conflict = inet6_csk_bind_conflict,
3fdadf7d 946#ifdef CONFIG_COMPAT
543d9cfe
ACM
947 .compat_setsockopt = compat_ipv6_setsockopt,
948 .compat_getsockopt = compat_ipv6_getsockopt,
3fdadf7d 949#endif
3df80d93
ACM
950};
951
952/*
953 * DCCP over IPv4 via INET6 API
954 */
3b401a81 955static const struct inet_connection_sock_af_ops dccp_ipv6_mapped = {
543d9cfe
ACM
956 .queue_xmit = ip_queue_xmit,
957 .send_check = dccp_v4_send_check,
958 .rebuild_header = inet_sk_rebuild_header,
959 .conn_request = dccp_v6_conn_request,
960 .syn_recv_sock = dccp_v6_request_recv_sock,
961 .net_header_len = sizeof(struct iphdr),
962 .setsockopt = ipv6_setsockopt,
963 .getsockopt = ipv6_getsockopt,
964 .addr2sockaddr = inet6_csk_addr2sockaddr,
965 .sockaddr_len = sizeof(struct sockaddr_in6),
3fdadf7d 966#ifdef CONFIG_COMPAT
543d9cfe
ACM
967 .compat_setsockopt = compat_ipv6_setsockopt,
968 .compat_getsockopt = compat_ipv6_getsockopt,
3fdadf7d 969#endif
3df80d93
ACM
970};
971
972/* NOTE: A lot of things set to zero explicitly by call to
973 * sk_alloc() so need not be done here.
974 */
975static int dccp_v6_init_sock(struct sock *sk)
976{
72478873
ACM
977 static __u8 dccp_v6_ctl_sock_initialized;
978 int err = dccp_init_sock(sk, dccp_v6_ctl_sock_initialized);
3df80d93 979
72478873
ACM
980 if (err == 0) {
981 if (unlikely(!dccp_v6_ctl_sock_initialized))
982 dccp_v6_ctl_sock_initialized = 1;
3df80d93 983 inet_csk(sk)->icsk_af_ops = &dccp_ipv6_af_ops;
72478873 984 }
3df80d93
ACM
985
986 return err;
987}
988
7d06b2e0 989static void dccp_v6_destroy_sock(struct sock *sk)
3df80d93 990{
3e0fadc5 991 dccp_destroy_sock(sk);
7d06b2e0 992 inet6_destroy_sock(sk);
3df80d93
ACM
993}
994
73c9e02c
GR
995static struct timewait_sock_ops dccp6_timewait_sock_ops = {
996 .twsk_obj_size = sizeof(struct dccp6_timewait_sock),
997};
998
3df80d93 999static struct proto dccp_v6_prot = {
543d9cfe
ACM
1000 .name = "DCCPv6",
1001 .owner = THIS_MODULE,
1002 .close = dccp_close,
1003 .connect = dccp_v6_connect,
1004 .disconnect = dccp_disconnect,
1005 .ioctl = dccp_ioctl,
1006 .init = dccp_v6_init_sock,
1007 .setsockopt = dccp_setsockopt,
1008 .getsockopt = dccp_getsockopt,
1009 .sendmsg = dccp_sendmsg,
1010 .recvmsg = dccp_recvmsg,
1011 .backlog_rcv = dccp_v6_do_rcv,
77a6a471 1012 .hash = inet_hash,
ab1e0a13 1013 .unhash = inet_unhash,
543d9cfe 1014 .accept = inet_csk_accept,
ab1e0a13 1015 .get_port = inet_csk_get_port,
543d9cfe
ACM
1016 .shutdown = dccp_shutdown,
1017 .destroy = dccp_v6_destroy_sock,
1018 .orphan_count = &dccp_orphan_count,
1019 .max_header = MAX_DCCP_HEADER,
1020 .obj_size = sizeof(struct dccp6_sock),
3ab5aee7 1021 .slab_flags = SLAB_DESTROY_BY_RCU,
543d9cfe
ACM
1022 .rsk_prot = &dccp6_request_sock_ops,
1023 .twsk_prot = &dccp6_timewait_sock_ops,
39d8cda7 1024 .h.hashinfo = &dccp_hashinfo,
3fdadf7d 1025#ifdef CONFIG_COMPAT
543d9cfe
ACM
1026 .compat_setsockopt = compat_dccp_setsockopt,
1027 .compat_getsockopt = compat_dccp_getsockopt,
3fdadf7d 1028#endif
3df80d93
ACM
1029};
1030
41135cc8 1031static const struct inet6_protocol dccp_v6_protocol = {
45329e71
ACM
1032 .handler = dccp_v6_rcv,
1033 .err_handler = dccp_v6_err,
1034 .flags = INET6_PROTO_NOPOLICY | INET6_PROTO_FINAL,
3df80d93
ACM
1035};
1036
5708e868 1037static const struct proto_ops inet6_dccp_ops = {
543d9cfe
ACM
1038 .family = PF_INET6,
1039 .owner = THIS_MODULE,
1040 .release = inet6_release,
1041 .bind = inet6_bind,
1042 .connect = inet_stream_connect,
1043 .socketpair = sock_no_socketpair,
1044 .accept = inet_accept,
1045 .getname = inet6_getname,
1046 .poll = dccp_poll,
1047 .ioctl = inet6_ioctl,
1048 .listen = inet_dccp_listen,
1049 .shutdown = inet_shutdown,
1050 .setsockopt = sock_common_setsockopt,
1051 .getsockopt = sock_common_getsockopt,
1052 .sendmsg = inet_sendmsg,
1053 .recvmsg = sock_common_recvmsg,
1054 .mmap = sock_no_mmap,
1055 .sendpage = sock_no_sendpage,
3fdadf7d 1056#ifdef CONFIG_COMPAT
543d9cfe
ACM
1057 .compat_setsockopt = compat_sock_common_setsockopt,
1058 .compat_getsockopt = compat_sock_common_getsockopt,
3fdadf7d 1059#endif
3df80d93
ACM
1060};
1061
1062static struct inet_protosw dccp_v6_protosw = {
1063 .type = SOCK_DCCP,
1064 .protocol = IPPROTO_DCCP,
1065 .prot = &dccp_v6_prot,
1066 .ops = &inet6_dccp_ops,
d83d8461 1067 .flags = INET_PROTOSW_ICSK,
3df80d93
ACM
1068};
1069
2c8c1e72 1070static int __net_init dccp_v6_init_net(struct net *net)
8231bd27 1071{
d14a0ebd
GR
1072 if (dccp_hashinfo.bhash == NULL)
1073 return -ESOCKTNOSUPPORT;
334527d3 1074
d14a0ebd
GR
1075 return inet_ctl_sock_create(&net->dccp.v6_ctl_sk, PF_INET6,
1076 SOCK_DCCP, IPPROTO_DCCP, net);
8231bd27
PE
1077}
1078
2c8c1e72 1079static void __net_exit dccp_v6_exit_net(struct net *net)
8231bd27 1080{
334527d3 1081 inet_ctl_sock_destroy(net->dccp.v6_ctl_sk);
8231bd27
PE
1082}
1083
1084static struct pernet_operations dccp_v6_ops = {
1085 .init = dccp_v6_init_net,
1086 .exit = dccp_v6_exit_net,
1087};
1088
3df80d93
ACM
1089static int __init dccp_v6_init(void)
1090{
1091 int err = proto_register(&dccp_v6_prot, 1);
1092
1093 if (err != 0)
1094 goto out;
1095
1096 err = inet6_add_protocol(&dccp_v6_protocol, IPPROTO_DCCP);
1097 if (err != 0)
1098 goto out_unregister_proto;
1099
1100 inet6_register_protosw(&dccp_v6_protosw);
72478873 1101
8231bd27
PE
1102 err = register_pernet_subsys(&dccp_v6_ops);
1103 if (err != 0)
1104 goto out_destroy_ctl_sock;
3df80d93
ACM
1105out:
1106 return err;
8231bd27
PE
1107
1108out_destroy_ctl_sock:
72478873
ACM
1109 inet6_del_protocol(&dccp_v6_protocol, IPPROTO_DCCP);
1110 inet6_unregister_protosw(&dccp_v6_protosw);
3df80d93
ACM
1111out_unregister_proto:
1112 proto_unregister(&dccp_v6_prot);
1113 goto out;
1114}
1115
1116static void __exit dccp_v6_exit(void)
1117{
8231bd27 1118 unregister_pernet_subsys(&dccp_v6_ops);
3df80d93
ACM
1119 inet6_del_protocol(&dccp_v6_protocol, IPPROTO_DCCP);
1120 inet6_unregister_protosw(&dccp_v6_protosw);
1121 proto_unregister(&dccp_v6_prot);
1122}
1123
1124module_init(dccp_v6_init);
1125module_exit(dccp_v6_exit);
1126
1127/*
1128 * __stringify doesn't likes enums, so use SOCK_DCCP (6) and IPPROTO_DCCP (33)
1129 * values directly, Also cover the case where the protocol is not specified,
1130 * i.e. net-pf-PF_INET6-proto-0-type-SOCK_DCCP
1131 */
7131c6c7
JD
1132MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_INET6, 33, 6);
1133MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_INET6, 0, 6);
3df80d93
ACM
1134MODULE_LICENSE("GPL");
1135MODULE_AUTHOR("Arnaldo Carvalho de Melo <acme@mandriva.com>");
1136MODULE_DESCRIPTION("DCCPv6 - Datagram Congestion Controlled Protocol");
This page took 0.818474 seconds and 5 git commands to generate.