ipv6.c 30.1 KB
Newer Older
1 2
/*
 *	DCCP over IPv6
A
Arnaldo Carvalho de Melo 已提交
3
 *	Linux INET6 implementation
4 5 6 7 8 9 10 11 12 13 14 15 16
 *
 *	Based on net/dccp6/ipv6.c
 *
 *	Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
 *
 *	This program is free software; you can redistribute it and/or
 *      modify it under the terms of the GNU General Public License
 *      as published by the Free Software Foundation; either version
 *      2 of the License, or (at your option) any later version.
 */

#include <linux/module.h>
#include <linux/random.h>
17
#include <linux/slab.h>
18 19 20 21 22
#include <linux/xfrm.h>

#include <net/addrconf.h>
#include <net/inet_common.h>
#include <net/inet_hashtables.h>
23
#include <net/inet_sock.h>
24 25 26 27 28 29
#include <net/inet6_connection_sock.h>
#include <net/inet6_hashtables.h>
#include <net/ip6_route.h>
#include <net/ipv6.h>
#include <net/protocol.h>
#include <net/transp_v6.h>
30
#include <net/ip6_checksum.h>
31
#include <net/xfrm.h>
32
#include <net/secure_seq.h>
33 34 35

#include "dccp.h"
#include "ipv6.h"
36
#include "feat.h"
37

38
/* The per-net dccp.v6_ctl_sk is used for sending RSTs and ACKs */
39

40 41
static const struct inet_connection_sock_af_ops dccp_ipv6_mapped;
static const struct inet_connection_sock_af_ops dccp_ipv6_af_ops;
42

43
/* add pseudo-header to DCCP checksum stored in skb->csum */
44
static inline __sum16 dccp_v6_csum_finish(struct sk_buff *skb,
45 46
				      const struct in6_addr *saddr,
				      const struct in6_addr *daddr)
47
{
48 49 50
	return csum_ipv6_magic(saddr, daddr, skb->len, IPPROTO_DCCP, skb->csum);
}

51
static inline void dccp_v6_send_check(struct sock *sk, struct sk_buff *skb)
52 53 54 55 56
{
	struct ipv6_pinfo *np = inet6_sk(sk);
	struct dccp_hdr *dh = dccp_hdr(skb);

	dccp_csum_outgoing(skb);
57
	dh->dccph_checksum = dccp_v6_csum_finish(skb, &np->saddr, &sk->sk_v6_daddr);
58 59
}

60
static inline __u64 dccp_v6_init_sequence(struct sk_buff *skb)
61
{
62 63
	return secure_dccpv6_sequence_number(ipv6_hdr(skb)->daddr.s6_addr32,
					     ipv6_hdr(skb)->saddr.s6_addr32,
64 65 66
					     dccp_hdr(skb)->dccph_dport,
					     dccp_hdr(skb)->dccph_sport     );

67 68 69
}

static void dccp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
70
			u8 type, u8 code, int offset, __be32 info)
71
{
72
	const struct ipv6hdr *hdr = (const struct ipv6hdr *)skb->data;
73
	const struct dccp_hdr *dh = (struct dccp_hdr *)(skb->data + offset);
74
	struct dccp_sock *dp;
75 76 77 78
	struct ipv6_pinfo *np;
	struct sock *sk;
	int err;
	__u64 seq;
79
	struct net *net = dev_net(skb->dev);
80

81 82
	if (skb->len < offset + sizeof(*dh) ||
	    skb->len < offset + __dccp_basic_hdr_len(dh)) {
83 84
		ICMP6_INC_STATS_BH(net, __in6_dev_get(skb->dev),
				   ICMP6_MIB_INERRORS);
85 86 87
		return;
	}

88
	sk = inet6_lookup(net, &dccp_hashinfo,
89
			&hdr->daddr, dh->dccph_dport,
90
			&hdr->saddr, dh->dccph_sport, inet6_iif(skb));
91 92

	if (sk == NULL) {
93 94
		ICMP6_INC_STATS_BH(net, __in6_dev_get(skb->dev),
				   ICMP6_MIB_INERRORS);
95 96 97 98
		return;
	}

	if (sk->sk_state == DCCP_TIME_WAIT) {
99
		inet_twsk_put(inet_twsk(sk));
100 101 102 103 104
		return;
	}

	bh_lock_sock(sk);
	if (sock_owned_by_user(sk))
105
		NET_INC_STATS_BH(net, LINUX_MIB_LOCKDROPPEDICMPS);
106 107 108 109

	if (sk->sk_state == DCCP_CLOSED)
		goto out;

110 111 112 113 114 115 116 117
	dp = dccp_sk(sk);
	seq = dccp_hdr_seq(dh);
	if ((1 << sk->sk_state) & ~(DCCPF_REQUESTING | DCCPF_LISTEN) &&
	    !between48(seq, dp->dccps_awl, dp->dccps_awh)) {
		NET_INC_STATS_BH(net, LINUX_MIB_OUTOFWINDOWICMPS);
		goto out;
	}

118 119
	np = inet6_sk(sk);

120 121 122
	if (type == NDISC_REDIRECT) {
		struct dst_entry *dst = __sk_dst_check(sk, np->dst_cookie);

123
		if (dst)
124
			dst->ops->redirect(dst, sk, skb);
125
		goto out;
126 127
	}

128 129 130
	if (type == ICMPV6_PKT_TOOBIG) {
		struct dst_entry *dst = NULL;

131 132 133
		if (!ip6_sk_accept_pmtu(sk))
			goto out;

134 135 136 137 138
		if (sock_owned_by_user(sk))
			goto out;
		if ((1 << sk->sk_state) & (DCCPF_LISTEN | DCCPF_CLOSED))
			goto out;

139 140 141 142 143
		dst = inet6_csk_update_pmtu(sk, ntohl(info));
		if (!dst)
			goto out;

		if (inet_csk(sk)->icsk_pmtu_cookie > dst_mtu(dst))
144 145 146 147 148 149 150 151
			dccp_sync_mss(sk, dst_mtu(dst));
		goto out;
	}

	icmpv6_err_convert(type, code, &err);

	/* Might be for an request_sock */
	switch (sk->sk_state) {
152
		struct request_sock *req;
153 154 155 156
	case DCCP_LISTEN:
		if (sock_owned_by_user(sk))
			goto out;

157
		req = inet6_csk_search_req(sk, dh->dccph_dport,
158 159
					   &hdr->daddr, &hdr->saddr,
					   inet6_iif(skb));
160
		if (!req)
161 162
			goto out;

A
Arnaldo Carvalho de Melo 已提交
163 164 165
		/*
		 * ICMPs are not backlogged, hence we cannot get an established
		 * socket here.
166
		 */
167
		WARN_ON(req->sk != NULL);
168

169 170
		if (!between48(seq, dccp_rsk(req)->dreq_iss,
				    dccp_rsk(req)->dreq_gss)) {
171
			NET_INC_STATS_BH(net, LINUX_MIB_OUTOFWINDOWICMPS);
172
			reqsk_put(req);
173 174 175
			goto out;
		}

176
		inet_csk_reqsk_queue_drop(sk, req);
177
		reqsk_put(req);
178 179 180 181
		goto out;

	case DCCP_REQUESTING:
	case DCCP_RESPOND:  /* Cannot happen.
A
Arnaldo Carvalho de Melo 已提交
182
			       It can, it SYNs are crossed. --ANK */
183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208
		if (!sock_owned_by_user(sk)) {
			DCCP_INC_STATS_BH(DCCP_MIB_ATTEMPTFAILS);
			sk->sk_err = err;
			/*
			 * Wake people up to see the error
			 * (see connect in sock.c)
			 */
			sk->sk_error_report(sk);
			dccp_done(sk);
		} else
			sk->sk_err_soft = err;
		goto out;
	}

	if (!sock_owned_by_user(sk) && np->recverr) {
		sk->sk_err = err;
		sk->sk_error_report(sk);
	} else
		sk->sk_err_soft = err;

out:
	bh_unlock_sock(sk);
	sock_put(sk);
}


C
Christoph Paasch 已提交
209
static int dccp_v6_send_response(struct sock *sk, struct request_sock *req)
210
{
211
	struct inet_request_sock *ireq = inet_rsk(req);
212 213
	struct ipv6_pinfo *np = inet6_sk(sk);
	struct sk_buff *skb;
214
	struct in6_addr *final_p, final;
215
	struct flowi6 fl6;
216
	int err = -1;
217
	struct dst_entry *dst;
218

219 220
	memset(&fl6, 0, sizeof(fl6));
	fl6.flowi6_proto = IPPROTO_DCCP;
221 222
	fl6.daddr = ireq->ir_v6_rmt_addr;
	fl6.saddr = ireq->ir_v6_loc_addr;
223
	fl6.flowlabel = 0;
224 225
	fl6.flowi6_oif = ireq->ir_iif;
	fl6.fl6_dport = ireq->ir_rmt_port;
E
Eric Dumazet 已提交
226
	fl6.fl6_sport = htons(ireq->ir_num);
227
	security_req_classify_flow(req, flowi6_to_flowi(&fl6));
228 229


230
	final_p = fl6_update_dst(&fl6, np->opt, &final);
231

232
	dst = ip6_dst_lookup_flow(sk, &fl6, final_p);
233 234 235
	if (IS_ERR(dst)) {
		err = PTR_ERR(dst);
		dst = NULL;
236
		goto done;
237
	}
238 239 240 241

	skb = dccp_make_response(sk, dst, req);
	if (skb != NULL) {
		struct dccp_hdr *dh = dccp_hdr(skb);
A
Arnaldo Carvalho de Melo 已提交
242

243
		dh->dccph_checksum = dccp_v6_csum_finish(skb,
244 245 246
							 &ireq->ir_v6_loc_addr,
							 &ireq->ir_v6_rmt_addr);
		fl6.daddr = ireq->ir_v6_rmt_addr;
247
		err = ip6_xmit(sk, skb, &fl6, np->opt, np->tclass);
248
		err = net_xmit_eval(err);
249 250 251
	}

done:
252
	dst_release(dst);
253 254 255 256 257
	return err;
}

static void dccp_v6_reqsk_destructor(struct request_sock *req)
{
258
	dccp_feat_list_purge(&dccp_rsk(req)->dreq_featneg);
259
	kfree_skb(inet_rsk(req)->pktopts);
260 261
}

262
static void dccp_v6_ctl_send_reset(struct sock *sk, struct sk_buff *rxskb)
263
{
264
	const struct ipv6hdr *rxip6h;
265
	struct sk_buff *skb;
266
	struct flowi6 fl6;
E
Eric Dumazet 已提交
267
	struct net *net = dev_net(skb_dst(rxskb)->dev);
268
	struct sock *ctl_sk = net->dccp.v6_ctl_sk;
E
Eric Dumazet 已提交
269
	struct dst_entry *dst;
270

271
	if (dccp_hdr(rxskb)->dccph_type == DCCP_PKT_RESET)
272 273 274
		return;

	if (!ipv6_unicast_destination(rxskb))
A
Arnaldo Carvalho de Melo 已提交
275
		return;
276

277
	skb = dccp_ctl_make_reset(ctl_sk, rxskb);
A
Arnaldo Carvalho de Melo 已提交
278
	if (skb == NULL)
279
		return;
280

281
	rxip6h = ipv6_hdr(rxskb);
282 283
	dccp_hdr(skb)->dccph_checksum = dccp_v6_csum_finish(skb, &rxip6h->saddr,
							    &rxip6h->daddr);
284

285
	memset(&fl6, 0, sizeof(fl6));
A
Alexey Dobriyan 已提交
286 287
	fl6.daddr = rxip6h->saddr;
	fl6.saddr = rxip6h->daddr;
288

289 290
	fl6.flowi6_proto = IPPROTO_DCCP;
	fl6.flowi6_oif = inet6_iif(rxskb);
291 292
	fl6.fl6_dport = dccp_hdr(skb)->dccph_dport;
	fl6.fl6_sport = dccp_hdr(skb)->dccph_sport;
293
	security_skb_classify_flow(rxskb, flowi6_to_flowi(&fl6));
294 295

	/* sk = NULL, but it is safe for now. RST socket required. */
296
	dst = ip6_dst_lookup_flow(ctl_sk, &fl6, NULL);
297 298
	if (!IS_ERR(dst)) {
		skb_dst_set(skb, dst);
299
		ip6_xmit(ctl_sk, skb, &fl6, NULL, 0);
300 301 302
		DCCP_INC_STATS_BH(DCCP_MIB_OUTSEGS);
		DCCP_INC_STATS_BH(DCCP_MIB_OUTRSTS);
		return;
303 304 305 306 307
	}

	kfree_skb(skb);
}

308 309 310 311 312 313 314
static struct request_sock_ops dccp6_request_sock_ops = {
	.family		= AF_INET6,
	.obj_size	= sizeof(struct dccp6_request_sock),
	.rtx_syn_ack	= dccp_v6_send_response,
	.send_ack	= dccp_reqsk_send_ack,
	.destructor	= dccp_v6_reqsk_destructor,
	.send_reset	= dccp_v6_ctl_send_reset,
315
	.syn_ack_timeout = dccp_syn_ack_timeout,
316 317
};

318 319 320
static struct sock *dccp_v6_hnd_req(struct sock *sk,struct sk_buff *skb)
{
	const struct dccp_hdr *dh = dccp_hdr(skb);
321
	const struct ipv6hdr *iph = ipv6_hdr(skb);
322
	struct request_sock *req;
323
	struct sock *nsk;
324 325 326

	req = inet6_csk_search_req(sk, dh->dccph_sport, &iph->saddr,
				   &iph->daddr, inet6_iif(skb));
327 328 329 330 331
	if (req) {
		nsk = dccp_check_req(sk, skb, req);
		reqsk_put(req);
		return nsk;
	}
332
	nsk = __inet6_lookup_established(sock_net(sk), &dccp_hashinfo,
333 334 335 336 337 338 339 340
					 &iph->saddr, dh->dccph_sport,
					 &iph->daddr, ntohs(dh->dccph_dport),
					 inet6_iif(skb));
	if (nsk != NULL) {
		if (nsk->sk_state != DCCP_TIME_WAIT) {
			bh_lock_sock(nsk);
			return nsk;
		}
341
		inet_twsk_put(inet_twsk(nsk));
342 343 344 345 346 347 348 349 350 351
		return NULL;
	}

	return sk;
}

static int dccp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
{
	struct request_sock *req;
	struct dccp_request_sock *dreq;
352
	struct inet_request_sock *ireq;
353
	struct ipv6_pinfo *np = inet6_sk(sk);
354
	const __be32 service = dccp_hdr_request(skb)->dccph_req_service;
355 356 357 358 359 360
	struct dccp_skb_cb *dcb = DCCP_SKB_CB(skb);

	if (skb->protocol == htons(ETH_P_IP))
		return dccp_v4_conn_request(sk, skb);

	if (!ipv6_unicast_destination(skb))
361
		return 0;	/* discard, don't send a reset here */
362 363

	if (dccp_bad_service_code(sk, service)) {
364
		dcb->dccpd_reset_code = DCCP_RESET_CODE_BAD_SERVICE_CODE;
365
		goto drop;
366
	}
367
	/*
A
Arnaldo Carvalho de Melo 已提交
368
	 * There are no SYN attacks on IPv6, yet...
369
	 */
370
	dcb->dccpd_reset_code = DCCP_RESET_CODE_TOO_BUSY;
371
	if (inet_csk_reqsk_queue_is_full(sk))
A
Arnaldo Carvalho de Melo 已提交
372
		goto drop;
373 374 375 376

	if (sk_acceptq_is_full(sk) && inet_csk_reqsk_queue_young(sk) > 1)
		goto drop;

377
	req = inet_reqsk_alloc(&dccp6_request_sock_ops, sk);
378 379 380
	if (req == NULL)
		goto drop;

381 382
	if (dccp_reqsk_init(req, dccp_sk(sk), skb))
		goto drop_and_free;
383

384 385 386 387
	dreq = dccp_rsk(req);
	if (dccp_parse_options(sk, dreq, skb))
		goto drop_and_free;

388 389 390
	if (security_inet_conn_request(sk, skb, req))
		goto drop_and_free;

391 392 393
	ireq = inet_rsk(req);
	ireq->ir_v6_rmt_addr = ipv6_hdr(skb)->saddr;
	ireq->ir_v6_loc_addr = ipv6_hdr(skb)->daddr;
E
Eric Dumazet 已提交
394
	ireq->ireq_family = AF_INET6;
395

396
	if (ipv6_opt_accepted(sk, skb, IP6CB(skb)) ||
397 398 399
	    np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo ||
	    np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim) {
		atomic_inc(&skb->users);
400
		ireq->pktopts = skb;
401
	}
402
	ireq->ir_iif = sk->sk_bound_dev_if;
403 404 405

	/* So that link locals have meaning */
	if (!sk->sk_bound_dev_if &&
406 407
	    ipv6_addr_type(&ireq->ir_v6_rmt_addr) & IPV6_ADDR_LINKLOCAL)
		ireq->ir_iif = inet6_iif(skb);
408

A
Arnaldo Carvalho de Melo 已提交
409
	/*
410 411
	 * Step 3: Process LISTEN state
	 *
412
	 *   Set S.ISR, S.GSR, S.SWL, S.SWH from packet or Init Cookie
413
	 *
414
	 * Setting S.SWL/S.SWH to is deferred to dccp_create_openreq_child().
415 416
	 */
	dreq->dreq_isr	   = dcb->dccpd_seq;
417
	dreq->dreq_gsr     = dreq->dreq_isr;
418
	dreq->dreq_iss	   = dccp_v6_init_sequence(skb);
419
	dreq->dreq_gss     = dreq->dreq_iss;
420 421
	dreq->dreq_service = service;

C
Christoph Paasch 已提交
422
	if (dccp_v6_send_response(sk, req))
423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439
		goto drop_and_free;

	inet6_csk_reqsk_queue_hash_add(sk, req, DCCP_TIMEOUT_INIT);
	return 0;

drop_and_free:
	reqsk_free(req);
drop:
	DCCP_INC_STATS_BH(DCCP_MIB_ATTEMPTFAILS);
	return -1;
}

static struct sock *dccp_v6_request_recv_sock(struct sock *sk,
					      struct sk_buff *skb,
					      struct request_sock *req,
					      struct dst_entry *dst)
{
440
	struct inet_request_sock *ireq = inet_rsk(req);
441 442 443 444 445 446 447 448 449 450
	struct ipv6_pinfo *newnp, *np = inet6_sk(sk);
	struct inet_sock *newinet;
	struct dccp6_sock *newdp6;
	struct sock *newsk;

	if (skb->protocol == htons(ETH_P_IP)) {
		/*
		 *	v6 mapped
		 */
		newsk = dccp_v4_request_recv_sock(sk, skb, req, dst);
A
Arnaldo Carvalho de Melo 已提交
451
		if (newsk == NULL)
452 453 454 455 456 457 458 459 460
			return NULL;

		newdp6 = (struct dccp6_sock *)newsk;
		newinet = inet_sk(newsk);
		newinet->pinet6 = &newdp6->inet6;
		newnp = inet6_sk(newsk);

		memcpy(newnp, np, sizeof(struct ipv6_pinfo));

461
		newnp->saddr = newsk->sk_v6_rcv_saddr;
462 463 464 465 466 467

		inet_csk(newsk)->icsk_af_ops = &dccp_ipv6_mapped;
		newsk->sk_backlog_rcv = dccp_v4_do_rcv;
		newnp->pktoptions  = NULL;
		newnp->opt	   = NULL;
		newnp->mcast_oif   = inet6_iif(skb);
468
		newnp->mcast_hops  = ipv6_hdr(skb)->hop_limit;
469 470 471 472 473 474 475 476 477 478 479

		/*
		 * No need to charge this sock to the relevant IPv6 refcnt debug socks count
		 * here, dccp_create_openreq_child now does this for us, see the comment in
		 * that function for the gory details. -acme
		 */

		/* It is tricky place. Until this moment IPv4 tcp
		   worked with IPv6 icsk.icsk_af_ops.
		   Sync it now.
		 */
480
		dccp_sync_mss(newsk, inet_csk(newsk)->icsk_pmtu_cookie);
481 482 483 484 485 486 487 488 489

		return newsk;
	}


	if (sk_acceptq_is_full(sk))
		goto out_overflow;

	if (dst == NULL) {
490
		struct in6_addr *final_p, final;
491 492 493 494
		struct flowi6 fl6;

		memset(&fl6, 0, sizeof(fl6));
		fl6.flowi6_proto = IPPROTO_DCCP;
495
		fl6.daddr = ireq->ir_v6_rmt_addr;
496
		final_p = fl6_update_dst(&fl6, np->opt, &final);
497
		fl6.saddr = ireq->ir_v6_loc_addr;
498
		fl6.flowi6_oif = sk->sk_bound_dev_if;
499
		fl6.fl6_dport = ireq->ir_rmt_port;
E
Eric Dumazet 已提交
500
		fl6.fl6_sport = htons(ireq->ir_num);
501 502
		security_sk_classify_flow(sk, flowi6_to_flowi(&fl6));

503
		dst = ip6_dst_lookup_flow(sk, &fl6, final_p);
504
		if (IS_ERR(dst))
505
			goto out;
A
Arnaldo Carvalho de Melo 已提交
506
	}
507 508 509

	newsk = dccp_create_openreq_child(sk, req, skb);
	if (newsk == NULL)
510
		goto out_nonewsk;
511 512 513 514 515 516 517

	/*
	 * No need to charge this sock to the relevant IPv6 refcnt debug socks
	 * count here, dccp_create_openreq_child now does this for us, see the
	 * comment in that function for the gory details. -acme
	 */

518
	__ip6_dst_store(newsk, dst, NULL, NULL);
A
Arnaldo Carvalho de Melo 已提交
519 520
	newsk->sk_route_caps = dst->dev->features & ~(NETIF_F_IP_CSUM |
						      NETIF_F_TSO);
521 522 523 524 525 526 527
	newdp6 = (struct dccp6_sock *)newsk;
	newinet = inet_sk(newsk);
	newinet->pinet6 = &newdp6->inet6;
	newnp = inet6_sk(newsk);

	memcpy(newnp, np, sizeof(struct ipv6_pinfo));

528 529 530 531
	newsk->sk_v6_daddr	= ireq->ir_v6_rmt_addr;
	newnp->saddr		= ireq->ir_v6_loc_addr;
	newsk->sk_v6_rcv_saddr	= ireq->ir_v6_loc_addr;
	newsk->sk_bound_dev_if	= ireq->ir_iif;
532

A
Arnaldo Carvalho de Melo 已提交
533
	/* Now IPv6 options...
534 535 536

	   First: no IPv4 options.
	 */
537
	newinet->inet_opt = NULL;
538 539 540 541 542 543

	/* Clone RX bits */
	newnp->rxopt.all = np->rxopt.all;

	/* Clone pktoptions received with SYN */
	newnp->pktoptions = NULL;
544 545 546 547
	if (ireq->pktopts != NULL) {
		newnp->pktoptions = skb_clone(ireq->pktopts, GFP_ATOMIC);
		consume_skb(ireq->pktopts);
		ireq->pktopts = NULL;
548 549 550 551 552
		if (newnp->pktoptions)
			skb_set_owner_r(newnp->pktoptions, newsk);
	}
	newnp->opt	  = NULL;
	newnp->mcast_oif  = inet6_iif(skb);
553
	newnp->mcast_hops = ipv6_hdr(skb)->hop_limit;
554

A
Arnaldo Carvalho de Melo 已提交
555 556 557 558 559
	/*
	 * Clone native IPv6 options from listening socket (if any)
	 *
	 * Yes, keeping reference count would be much more clever, but we make
	 * one more one thing there: reattach optmem to newsk.
560
	 */
561 562
	if (np->opt != NULL)
		newnp->opt = ipv6_dup_options(newsk, np->opt);
563

564
	inet_csk(newsk)->icsk_ext_hdr_len = 0;
A
Arnaldo Carvalho de Melo 已提交
565
	if (newnp->opt != NULL)
566 567
		inet_csk(newsk)->icsk_ext_hdr_len = (newnp->opt->opt_nflen +
						     newnp->opt->opt_flen);
568 569 570

	dccp_sync_mss(newsk, dst_mtu(dst));

E
Eric Dumazet 已提交
571 572
	newinet->inet_daddr = newinet->inet_saddr = LOOPBACK4_IPV6;
	newinet->inet_rcv_saddr = LOOPBACK4_IPV6;
573

574
	if (__inet_inherit_port(sk, newsk) < 0) {
575 576
		inet_csk_prepare_forced_close(newsk);
		dccp_done(newsk);
577 578
		goto out;
	}
E
Eric Dumazet 已提交
579
	__inet_hash(newsk, NULL);
580 581 582 583

	return newsk;

out_overflow:
584
	NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENOVERFLOWS);
585 586
out_nonewsk:
	dst_release(dst);
587
out:
588
	NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENDROPS);
589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615
	return NULL;
}

/* The socket must have it's spinlock held when we get
 * here.
 *
 * We have a potential double-lock case here, so even when
 * doing backlog processing we use the BH locking scheme.
 * This is because we cannot sleep with the original spinlock
 * held.
 */
static int dccp_v6_do_rcv(struct sock *sk, struct sk_buff *skb)
{
	struct ipv6_pinfo *np = inet6_sk(sk);
	struct sk_buff *opt_skb = NULL;

	/* Imagine: socket is IPv6. IPv4 packet arrives,
	   goes to IPv4 receive handler and backlogged.
	   From backlog it always goes here. Kerboom...
	   Fortunately, dccp_rcv_established and rcv_established
	   handle them correctly, but it is not case with
	   dccp_v6_hnd_req and dccp_v6_ctl_send_reset().   --ANK
	 */

	if (skb->protocol == htons(ETH_P_IP))
		return dccp_v4_do_rcv(sk, skb);

616
	if (sk_filter(sk, skb))
617 618 619
		goto discard;

	/*
A
Arnaldo Carvalho de Melo 已提交
620 621
	 * socket locking is here for SMP purposes as backlog rcv is currently
	 * called with bh processing disabled.
622 623 624 625 626 627 628 629 630 631 632 633 634
	 */

	/* Do Stevens' IPV6_PKTOPTIONS.

	   Yes, guys, it is the only place in our code, where we
	   may make it not affecting IPv4.
	   The rest of code is protocol independent,
	   and I do not like idea to uglify IPv4.

	   Actually, all the idea behind IPV6_PKTOPTIONS
	   looks not very well thought. For now we latch
	   options, received in the last packet, enqueued
	   by tcp. Feel free to propose better solution.
635
					       --ANK (980728)
636 637
	 */
	if (np->rxopt.all)
638 639 640 641
	/*
	 * FIXME: Add handling of IPV6_PKTOPTIONS skb. See the comments below
	 *        (wrt ipv6_pktopions) and net/ipv6/tcp_ipv6.c for an example.
	 */
642 643 644 645 646
		opt_skb = skb_clone(skb, GFP_ATOMIC);

	if (sk->sk_state == DCCP_OPEN) { /* Fast path */
		if (dccp_rcv_established(sk, skb, dccp_hdr(skb), skb->len))
			goto reset;
D
David S. Miller 已提交
647
		if (opt_skb) {
648
			/* XXX This is where we would goto ipv6_pktoptions. */
D
David S. Miller 已提交
649 650
			__kfree_skb(opt_skb);
		}
651 652 653
		return 0;
	}

654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677
	/*
	 *  Step 3: Process LISTEN state
	 *     If S.state == LISTEN,
	 *	 If P.type == Request or P contains a valid Init Cookie option,
	 *	      (* Must scan the packet's options to check for Init
	 *		 Cookies.  Only Init Cookies are processed here,
	 *		 however; other options are processed in Step 8.  This
	 *		 scan need only be performed if the endpoint uses Init
	 *		 Cookies *)
	 *	      (* Generate a new socket and switch to that socket *)
	 *	      Set S := new socket for this port pair
	 *	      S.state = RESPOND
	 *	      Choose S.ISS (initial seqno) or set from Init Cookies
	 *	      Initialize S.GAR := S.ISS
	 *	      Set S.ISR, S.GSR, S.SWL, S.SWH from packet or Init Cookies
	 *	      Continue with S.state == RESPOND
	 *	      (* A Response packet will be generated in Step 11 *)
	 *	 Otherwise,
	 *	      Generate Reset(No Connection) unless P.type == Reset
	 *	      Drop packet and return
	 *
	 * NOTE: the check for the packet types is done in
	 *	 dccp_rcv_state_process
	 */
A
Arnaldo Carvalho de Melo 已提交
678
	if (sk->sk_state == DCCP_LISTEN) {
679 680
		struct sock *nsk = dccp_v6_hnd_req(sk, skb);

A
Arnaldo Carvalho de Melo 已提交
681 682
		if (nsk == NULL)
			goto discard;
683 684 685 686 687
		/*
		 * Queue it on the new socket if the new socket is active,
		 * otherwise we just shortcircuit this and continue with
		 * the new socket..
		 */
688
		if (nsk != sk) {
689 690
			if (dccp_child_process(sk, nsk, skb))
				goto reset;
A
Arnaldo Carvalho de Melo 已提交
691
			if (opt_skb != NULL)
692 693 694 695 696 697 698
				__kfree_skb(opt_skb);
			return 0;
		}
	}

	if (dccp_rcv_state_process(sk, skb, dccp_hdr(skb), skb->len))
		goto reset;
D
David S. Miller 已提交
699
	if (opt_skb) {
700
		/* XXX This is where we would goto ipv6_pktoptions. */
D
David S. Miller 已提交
701 702
		__kfree_skb(opt_skb);
	}
703 704 705
	return 0;

reset:
706
	dccp_v6_ctl_send_reset(sk, skb);
707
discard:
A
Arnaldo Carvalho de Melo 已提交
708
	if (opt_skb != NULL)
709 710 711 712 713
		__kfree_skb(opt_skb);
	kfree_skb(skb);
	return 0;
}

714
static int dccp_v6_rcv(struct sk_buff *skb)
715 716 717
{
	const struct dccp_hdr *dh;
	struct sock *sk;
718
	int min_cov;
719

720
	/* Step 1: Check header basics */
721 722 723 724

	if (dccp_invalid_packet(skb))
		goto discard_it;

725
	/* Step 1: If header checksum is incorrect, drop packet and return. */
726 727
	if (dccp_v6_csum_finish(skb, &ipv6_hdr(skb)->saddr,
				     &ipv6_hdr(skb)->daddr)) {
728
		DCCP_WARN("dropped packet with invalid checksum\n");
729 730 731
		goto discard_it;
	}

732 733
	dh = dccp_hdr(skb);

734
	DCCP_SKB_CB(skb)->dccpd_seq  = dccp_hdr_seq(dh);
735 736 737 738 739 740 741 742
	DCCP_SKB_CB(skb)->dccpd_type = dh->dccph_type;

	if (dccp_packet_without_ack(skb))
		DCCP_SKB_CB(skb)->dccpd_ack_seq = DCCP_PKT_WITHOUT_ACK_SEQ;
	else
		DCCP_SKB_CB(skb)->dccpd_ack_seq = dccp_hdr_ack_seq(skb);

	/* Step 2:
743
	 *	Look up flow ID in table and get corresponding socket */
744
	sk = __inet6_lookup_skb(&dccp_hashinfo, skb,
E
Eric Dumazet 已提交
745 746
			        dh->dccph_sport, dh->dccph_dport,
				inet6_iif(skb));
A
Arnaldo Carvalho de Melo 已提交
747
	/*
748
	 * Step 2:
749
	 *	If no socket ...
750
	 */
751 752 753
	if (sk == NULL) {
		dccp_pr_debug("failed to look up flow ID in table and "
			      "get corresponding socket\n");
754
		goto no_dccp_socket;
755
	}
756

A
Arnaldo Carvalho de Melo 已提交
757
	/*
758
	 * Step 2:
759
	 *	... or S.state == TIMEWAIT,
760 761 762
	 *		Generate Reset(No Connection) unless P.type == Reset
	 *		Drop packet and return
	 */
763 764 765 766 767
	if (sk->sk_state == DCCP_TIME_WAIT) {
		dccp_pr_debug("sk->sk_state == DCCP_TIME_WAIT: do_time_wait\n");
		inet_twsk_put(inet_twsk(sk));
		goto no_dccp_socket;
	}
768

769 770
	/*
	 * RFC 4340, sec. 9.2.1: Minimum Checksum Coverage
771 772
	 *	o if MinCsCov = 0, only packets with CsCov = 0 are accepted
	 *	o if MinCsCov > 0, also accept packets with CsCov >= MinCsCov
773 774 775 776 777 778 779 780 781
	 */
	min_cov = dccp_sk(sk)->dccps_pcrlen;
	if (dh->dccph_cscov  &&  (min_cov == 0 || dh->dccph_cscov < min_cov))  {
		dccp_pr_debug("Packet CsCov %d does not satisfy MinCsCov %d\n",
			      dh->dccph_cscov, min_cov);
		/* FIXME: send Data Dropped option (see also dccp_v4_rcv) */
		goto discard_and_relse;
	}

782 783 784
	if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb))
		goto discard_and_relse;

785
	return sk_receive_skb(sk, skb, 1) ? -1 : 0;
786 787 788 789 790 791

no_dccp_socket:
	if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb))
		goto discard_it;
	/*
	 * Step 2:
792
	 *	If no socket ...
793 794 795 796 797 798
	 *		Generate Reset(No Connection) unless P.type == Reset
	 *		Drop packet and return
	 */
	if (dh->dccph_type != DCCP_PKT_RESET) {
		DCCP_SKB_CB(skb)->dccpd_reset_code =
					DCCP_RESET_CODE_NO_CONNECTION;
799
		dccp_v6_ctl_send_reset(sk, skb);
800 801
	}

802
discard_it:
803 804 805 806 807 808 809 810
	kfree_skb(skb);
	return 0;

discard_and_relse:
	sock_put(sk);
	goto discard_it;
}

811 812 813 814 815 816 817 818
static int dccp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
			   int addr_len)
{
	struct sockaddr_in6 *usin = (struct sockaddr_in6 *)uaddr;
	struct inet_connection_sock *icsk = inet_csk(sk);
	struct inet_sock *inet = inet_sk(sk);
	struct ipv6_pinfo *np = inet6_sk(sk);
	struct dccp_sock *dp = dccp_sk(sk);
819
	struct in6_addr *saddr = NULL, *final_p, final;
820
	struct flowi6 fl6;
821 822 823 824 825 826 827 828 829 830 831 832
	struct dst_entry *dst;
	int addr_type;
	int err;

	dp->dccps_role = DCCP_ROLE_CLIENT;

	if (addr_len < SIN6_LEN_RFC2133)
		return -EINVAL;

	if (usin->sin6_family != AF_INET6)
		return -EAFNOSUPPORT;

833
	memset(&fl6, 0, sizeof(fl6));
834 835

	if (np->sndflow) {
836 837 838
		fl6.flowlabel = usin->sin6_flowinfo & IPV6_FLOWINFO_MASK;
		IP6_ECN_flow_init(fl6.flowlabel);
		if (fl6.flowlabel & IPV6_FLOWLABEL_MASK) {
839
			struct ip6_flowlabel *flowlabel;
840
			flowlabel = fl6_sock_lookup(sk, fl6.flowlabel);
841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874
			if (flowlabel == NULL)
				return -EINVAL;
			fl6_sock_release(flowlabel);
		}
	}
	/*
	 * connect() to INADDR_ANY means loopback (BSD'ism).
	 */
	if (ipv6_addr_any(&usin->sin6_addr))
		usin->sin6_addr.s6_addr[15] = 1;

	addr_type = ipv6_addr_type(&usin->sin6_addr);

	if (addr_type & IPV6_ADDR_MULTICAST)
		return -ENETUNREACH;

	if (addr_type & IPV6_ADDR_LINKLOCAL) {
		if (addr_len >= sizeof(struct sockaddr_in6) &&
		    usin->sin6_scope_id) {
			/* If interface is set while binding, indices
			 * must coincide.
			 */
			if (sk->sk_bound_dev_if &&
			    sk->sk_bound_dev_if != usin->sin6_scope_id)
				return -EINVAL;

			sk->sk_bound_dev_if = usin->sin6_scope_id;
		}

		/* Connect to link-local address requires an interface */
		if (!sk->sk_bound_dev_if)
			return -EINVAL;
	}

875
	sk->sk_v6_daddr = usin->sin6_addr;
876
	np->flow_label = fl6.flowlabel;
877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903

	/*
	 * DCCP over IPv4
	 */
	if (addr_type == IPV6_ADDR_MAPPED) {
		u32 exthdrlen = icsk->icsk_ext_hdr_len;
		struct sockaddr_in sin;

		SOCK_DEBUG(sk, "connect: ipv4 mapped\n");

		if (__ipv6_only_sock(sk))
			return -ENETUNREACH;

		sin.sin_family = AF_INET;
		sin.sin_port = usin->sin6_port;
		sin.sin_addr.s_addr = usin->sin6_addr.s6_addr32[3];

		icsk->icsk_af_ops = &dccp_ipv6_mapped;
		sk->sk_backlog_rcv = dccp_v4_do_rcv;

		err = dccp_v4_connect(sk, (struct sockaddr *)&sin, sizeof(sin));
		if (err) {
			icsk->icsk_ext_hdr_len = exthdrlen;
			icsk->icsk_af_ops = &dccp_ipv6_af_ops;
			sk->sk_backlog_rcv = dccp_v6_do_rcv;
			goto failure;
		}
904
		np->saddr = sk->sk_v6_rcv_saddr;
905 906 907
		return err;
	}

908 909
	if (!ipv6_addr_any(&sk->sk_v6_rcv_saddr))
		saddr = &sk->sk_v6_rcv_saddr;
910

911
	fl6.flowi6_proto = IPPROTO_DCCP;
912
	fl6.daddr = sk->sk_v6_daddr;
A
Alexey Dobriyan 已提交
913
	fl6.saddr = saddr ? *saddr : np->saddr;
914
	fl6.flowi6_oif = sk->sk_bound_dev_if;
915 916
	fl6.fl6_dport = usin->sin6_port;
	fl6.fl6_sport = inet->inet_sport;
917
	security_sk_classify_flow(sk, flowi6_to_flowi(&fl6));
918

919
	final_p = fl6_update_dst(&fl6, np->opt, &final);
920

921
	dst = ip6_dst_lookup_flow(sk, &fl6, final_p);
922 923
	if (IS_ERR(dst)) {
		err = PTR_ERR(dst);
924
		goto failure;
925
	}
926 927

	if (saddr == NULL) {
928
		saddr = &fl6.saddr;
929
		sk->sk_v6_rcv_saddr = *saddr;
930 931 932
	}

	/* set the source address */
A
Alexey Dobriyan 已提交
933
	np->saddr = *saddr;
E
Eric Dumazet 已提交
934
	inet->inet_rcv_saddr = LOOPBACK4_IPV6;
935 936 937 938 939 940 941 942

	__ip6_dst_store(sk, dst, NULL, NULL);

	icsk->icsk_ext_hdr_len = 0;
	if (np->opt != NULL)
		icsk->icsk_ext_hdr_len = (np->opt->opt_flen +
					  np->opt->opt_nflen);

E
Eric Dumazet 已提交
943
	inet->inet_dport = usin->sin6_port;
944 945 946 947 948

	dccp_set_state(sk, DCCP_REQUESTING);
	err = inet6_hash_connect(&dccp_death_row, sk);
	if (err)
		goto late_failure;
949 950

	dp->dccps_iss = secure_dccpv6_sequence_number(np->saddr.s6_addr32,
951
						      sk->sk_v6_daddr.s6_addr32,
E
Eric Dumazet 已提交
952 953
						      inet->inet_sport,
						      inet->inet_dport);
954 955 956 957 958 959 960 961 962 963
	err = dccp_connect(sk);
	if (err)
		goto late_failure;

	return 0;

late_failure:
	dccp_set_state(sk, DCCP_CLOSED);
	__sk_dst_reset(sk);
failure:
E
Eric Dumazet 已提交
964
	inet->inet_dport = 0;
965 966 967 968
	sk->sk_route_caps = 0;
	return err;
}

969
static const struct inet_connection_sock_af_ops dccp_ipv6_af_ops = {
970 971 972 973 974 975 976 977 978 979
	.queue_xmit	   = inet6_csk_xmit,
	.send_check	   = dccp_v6_send_check,
	.rebuild_header	   = inet6_sk_rebuild_header,
	.conn_request	   = dccp_v6_conn_request,
	.syn_recv_sock	   = dccp_v6_request_recv_sock,
	.net_header_len	   = sizeof(struct ipv6hdr),
	.setsockopt	   = ipv6_setsockopt,
	.getsockopt	   = ipv6_getsockopt,
	.addr2sockaddr	   = inet6_csk_addr2sockaddr,
	.sockaddr_len	   = sizeof(struct sockaddr_in6),
980
	.bind_conflict	   = inet6_csk_bind_conflict,
981
#ifdef CONFIG_COMPAT
982 983
	.compat_setsockopt = compat_ipv6_setsockopt,
	.compat_getsockopt = compat_ipv6_getsockopt,
984
#endif
985 986 987 988 989
};

/*
 *	DCCP over IPv4 via INET6 API
 */
990
static const struct inet_connection_sock_af_ops dccp_ipv6_mapped = {
991 992 993 994 995 996 997 998 999 1000
	.queue_xmit	   = ip_queue_xmit,
	.send_check	   = dccp_v4_send_check,
	.rebuild_header	   = inet_sk_rebuild_header,
	.conn_request	   = dccp_v6_conn_request,
	.syn_recv_sock	   = dccp_v6_request_recv_sock,
	.net_header_len	   = sizeof(struct iphdr),
	.setsockopt	   = ipv6_setsockopt,
	.getsockopt	   = ipv6_getsockopt,
	.addr2sockaddr	   = inet6_csk_addr2sockaddr,
	.sockaddr_len	   = sizeof(struct sockaddr_in6),
1001
#ifdef CONFIG_COMPAT
1002 1003
	.compat_setsockopt = compat_ipv6_setsockopt,
	.compat_getsockopt = compat_ipv6_getsockopt,
1004
#endif
1005 1006 1007 1008 1009 1010 1011
};

/* NOTE: A lot of things set to zero explicitly by call to
 *       sk_alloc() so need not be done here.
 */
static int dccp_v6_init_sock(struct sock *sk)
{
1012 1013
	static __u8 dccp_v6_ctl_sock_initialized;
	int err = dccp_init_sock(sk, dccp_v6_ctl_sock_initialized);
1014

1015 1016 1017
	if (err == 0) {
		if (unlikely(!dccp_v6_ctl_sock_initialized))
			dccp_v6_ctl_sock_initialized = 1;
1018
		inet_csk(sk)->icsk_af_ops = &dccp_ipv6_af_ops;
1019
	}
1020 1021 1022 1023

	return err;
}

1024
static void dccp_v6_destroy_sock(struct sock *sk)
1025
{
1026
	dccp_destroy_sock(sk);
1027
	inet6_destroy_sock(sk);
1028 1029
}

1030 1031 1032 1033
static struct timewait_sock_ops dccp6_timewait_sock_ops = {
	.twsk_obj_size	= sizeof(struct dccp6_timewait_sock),
};

1034
static struct proto dccp_v6_prot = {
1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046
	.name		   = "DCCPv6",
	.owner		   = THIS_MODULE,
	.close		   = dccp_close,
	.connect	   = dccp_v6_connect,
	.disconnect	   = dccp_disconnect,
	.ioctl		   = dccp_ioctl,
	.init		   = dccp_v6_init_sock,
	.setsockopt	   = dccp_setsockopt,
	.getsockopt	   = dccp_getsockopt,
	.sendmsg	   = dccp_sendmsg,
	.recvmsg	   = dccp_recvmsg,
	.backlog_rcv	   = dccp_v6_do_rcv,
E
Eric Dumazet 已提交
1047
	.hash		   = inet_hash,
1048
	.unhash		   = inet_unhash,
1049
	.accept		   = inet_csk_accept,
1050
	.get_port	   = inet_csk_get_port,
1051 1052 1053 1054 1055
	.shutdown	   = dccp_shutdown,
	.destroy	   = dccp_v6_destroy_sock,
	.orphan_count	   = &dccp_orphan_count,
	.max_header	   = MAX_DCCP_HEADER,
	.obj_size	   = sizeof(struct dccp6_sock),
1056
	.slab_flags	   = SLAB_DESTROY_BY_RCU,
1057 1058
	.rsk_prot	   = &dccp6_request_sock_ops,
	.twsk_prot	   = &dccp6_timewait_sock_ops,
1059
	.h.hashinfo	   = &dccp_hashinfo,
1060
#ifdef CONFIG_COMPAT
1061 1062
	.compat_setsockopt = compat_dccp_setsockopt,
	.compat_getsockopt = compat_dccp_getsockopt,
1063
#endif
1064 1065
};

1066
static const struct inet6_protocol dccp_v6_protocol = {
A
Arnaldo Carvalho de Melo 已提交
1067 1068 1069
	.handler	= dccp_v6_rcv,
	.err_handler	= dccp_v6_err,
	.flags		= INET6_PROTO_NOPOLICY | INET6_PROTO_FINAL,
1070 1071
};

1072
static const struct proto_ops inet6_dccp_ops = {
1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090
	.family		   = PF_INET6,
	.owner		   = THIS_MODULE,
	.release	   = inet6_release,
	.bind		   = inet6_bind,
	.connect	   = inet_stream_connect,
	.socketpair	   = sock_no_socketpair,
	.accept		   = inet_accept,
	.getname	   = inet6_getname,
	.poll		   = dccp_poll,
	.ioctl		   = inet6_ioctl,
	.listen		   = inet_dccp_listen,
	.shutdown	   = inet_shutdown,
	.setsockopt	   = sock_common_setsockopt,
	.getsockopt	   = sock_common_getsockopt,
	.sendmsg	   = inet_sendmsg,
	.recvmsg	   = sock_common_recvmsg,
	.mmap		   = sock_no_mmap,
	.sendpage	   = sock_no_sendpage,
1091
#ifdef CONFIG_COMPAT
1092 1093
	.compat_setsockopt = compat_sock_common_setsockopt,
	.compat_getsockopt = compat_sock_common_getsockopt,
1094
#endif
1095 1096 1097 1098 1099 1100 1101
};

static struct inet_protosw dccp_v6_protosw = {
	.type		= SOCK_DCCP,
	.protocol	= IPPROTO_DCCP,
	.prot		= &dccp_v6_prot,
	.ops		= &inet6_dccp_ops,
1102
	.flags		= INET_PROTOSW_ICSK,
1103 1104
};

1105
static int __net_init dccp_v6_init_net(struct net *net)
1106
{
1107 1108
	if (dccp_hashinfo.bhash == NULL)
		return -ESOCKTNOSUPPORT;
1109

1110 1111
	return inet_ctl_sock_create(&net->dccp.v6_ctl_sk, PF_INET6,
				    SOCK_DCCP, IPPROTO_DCCP, net);
1112 1113
}

1114
static void __net_exit dccp_v6_exit_net(struct net *net)
1115
{
1116
	inet_ctl_sock_destroy(net->dccp.v6_ctl_sk);
1117 1118 1119 1120 1121 1122 1123
}

static struct pernet_operations dccp_v6_ops = {
	.init   = dccp_v6_init_net,
	.exit   = dccp_v6_exit_net,
};

1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135
static int __init dccp_v6_init(void)
{
	int err = proto_register(&dccp_v6_prot, 1);

	if (err != 0)
		goto out;

	err = inet6_add_protocol(&dccp_v6_protocol, IPPROTO_DCCP);
	if (err != 0)
		goto out_unregister_proto;

	inet6_register_protosw(&dccp_v6_protosw);
1136

1137 1138 1139
	err = register_pernet_subsys(&dccp_v6_ops);
	if (err != 0)
		goto out_destroy_ctl_sock;
1140 1141
out:
	return err;
1142 1143

out_destroy_ctl_sock:
1144 1145
	inet6_del_protocol(&dccp_v6_protocol, IPPROTO_DCCP);
	inet6_unregister_protosw(&dccp_v6_protosw);
1146 1147 1148 1149 1150 1151 1152
out_unregister_proto:
	proto_unregister(&dccp_v6_prot);
	goto out;
}

static void __exit dccp_v6_exit(void)
{
1153
	unregister_pernet_subsys(&dccp_v6_ops);
1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166
	inet6_del_protocol(&dccp_v6_protocol, IPPROTO_DCCP);
	inet6_unregister_protosw(&dccp_v6_protosw);
	proto_unregister(&dccp_v6_prot);
}

module_init(dccp_v6_init);
module_exit(dccp_v6_exit);

/*
 * __stringify doesn't likes enums, so use SOCK_DCCP (6) and IPPROTO_DCCP (33)
 * values directly, Also cover the case where the protocol is not specified,
 * i.e. net-pf-PF_INET6-proto-0-type-SOCK_DCCP
 */
1167 1168
MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_INET6, 33, 6);
MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_INET6, 0, 6);
1169 1170 1171
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Arnaldo Carvalho de Melo <acme@mandriva.com>");
MODULE_DESCRIPTION("DCCPv6 - Datagram Congestion Controlled Protocol");