blob: 25826b1bf68516ba8d30b89283aeb7554f8e4c70 [file] [log] [blame]
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001/*
2 * DCCP over IPv6
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -08003 * Linux INET6 implementation
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08004 *
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
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -080015#include <linux/module.h>
16#include <linux/random.h>
17#include <linux/xfrm.h>
18
19#include <net/addrconf.h>
20#include <net/inet_common.h>
21#include <net/inet_hashtables.h>
Arnaldo Carvalho de Melo14c85022005-12-27 02:43:12 -020022#include <net/inet_sock.h>
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -080023#include <net/inet6_connection_sock.h>
24#include <net/inet6_hashtables.h>
25#include <net/ip6_route.h>
26#include <net/ipv6.h>
27#include <net/protocol.h>
28#include <net/transp_v6.h>
David S. Milleraa0e4e42006-01-06 22:55:39 -080029#include <net/ip6_checksum.h>
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -080030#include <net/xfrm.h>
31
32#include "dccp.h"
33#include "ipv6.h"
Ian McDonald4b79f0a2006-07-23 23:33:28 -070034#include "feat.h"
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -080035
Pavel Emelyanov13f51d82008-04-14 02:38:45 -070036/* The per-net dccp.v6_ctl_sk is used for sending RSTs and ACKs */
Arnaldo Carvalho de Melo72478872006-03-20 22:00:37 -080037
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -080038static struct inet_connection_sock_af_ops dccp_ipv6_mapped;
39static struct inet_connection_sock_af_ops dccp_ipv6_af_ops;
40
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -080041static void dccp_v6_hash(struct sock *sk)
42{
43 if (sk->sk_state != DCCP_CLOSED) {
44 if (inet_csk(sk)->icsk_af_ops == &dccp_ipv6_mapped) {
Arnaldo Carvalho de Meloab1e0a12008-02-03 04:06:04 -080045 inet_hash(sk);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -080046 return;
47 }
48 local_bh_disable();
Arnaldo Carvalho de Meloab1e0a12008-02-03 04:06:04 -080049 __inet6_hash(sk);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -080050 local_bh_enable();
51 }
52}
53
Gerrit Renker6f4e5ff2006-11-10 17:43:06 -020054/* add pseudo-header to DCCP checksum stored in skb->csum */
Al Viro868c86b2006-11-14 21:35:48 -080055static inline __sum16 dccp_v6_csum_finish(struct sk_buff *skb,
Gerrit Renker6f4e5ff2006-11-10 17:43:06 -020056 struct in6_addr *saddr,
57 struct in6_addr *daddr)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -080058{
Gerrit Renker6f4e5ff2006-11-10 17:43:06 -020059 return csum_ipv6_magic(saddr, daddr, skb->len, IPPROTO_DCCP, skb->csum);
60}
61
62static inline void dccp_v6_send_check(struct sock *sk, int unused_value,
63 struct sk_buff *skb)
64{
65 struct ipv6_pinfo *np = inet6_sk(sk);
66 struct dccp_hdr *dh = dccp_hdr(skb);
67
68 dccp_csum_outgoing(skb);
69 dh->dccph_checksum = dccp_v6_csum_finish(skb, &np->saddr, &np->daddr);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -080070}
71
Al Viro7d533f92006-11-14 21:51:36 -080072static inline __u32 secure_dccpv6_sequence_number(__be32 *saddr, __be32 *daddr,
Arnaldo Carvalho de Melo8109b022006-12-10 16:01:18 -020073 __be16 sport, __be16 dport )
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -080074{
Gerrit Renkerd7f73652006-11-13 13:34:38 -020075 return secure_tcpv6_sequence_number(saddr, daddr, sport, dport);
76}
77
78static inline __u32 dccp_v6_init_sequence(struct sk_buff *skb)
79{
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -070080 return secure_dccpv6_sequence_number(ipv6_hdr(skb)->daddr.s6_addr32,
81 ipv6_hdr(skb)->saddr.s6_addr32,
Gerrit Renkerd7f73652006-11-13 13:34:38 -020082 dccp_hdr(skb)->dccph_dport,
83 dccp_hdr(skb)->dccph_sport );
84
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -080085}
86
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -080087static void dccp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
Andrea Bittau60fe62e2006-03-20 19:23:32 -080088 int type, int code, int offset, __be32 info)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -080089{
90 struct ipv6hdr *hdr = (struct ipv6hdr *)skb->data;
91 const struct dccp_hdr *dh = (struct dccp_hdr *)(skb->data + offset);
Wei Yongjune0bcfb02008-07-26 11:59:10 +010092 struct dccp_sock *dp;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -080093 struct ipv6_pinfo *np;
94 struct sock *sk;
95 int err;
96 __u64 seq;
Pavel Emelyanovca12a1a2008-07-16 20:28:42 -070097 struct net *net = dev_net(skb->dev);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -080098
Pavel Emelyanovca12a1a2008-07-16 20:28:42 -070099 sk = inet6_lookup(net, &dccp_hashinfo,
Pavel Emelyanov671a1c72008-04-13 22:33:06 -0700100 &hdr->daddr, dh->dccph_dport,
Pavel Emelyanovd86e0da2008-01-31 05:07:21 -0800101 &hdr->saddr, dh->dccph_sport, inet6_iif(skb));
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800102
103 if (sk == NULL) {
104 ICMP6_INC_STATS_BH(__in6_dev_get(skb->dev), ICMP6_MIB_INERRORS);
105 return;
106 }
107
108 if (sk->sk_state == DCCP_TIME_WAIT) {
YOSHIFUJI Hideaki9469c7b2006-10-10 19:41:46 -0700109 inet_twsk_put(inet_twsk(sk));
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800110 return;
111 }
112
113 bh_lock_sock(sk);
114 if (sock_owned_by_user(sk))
Pavel Emelyanovde0744a2008-07-16 20:31:16 -0700115 NET_INC_STATS_BH(net, LINUX_MIB_LOCKDROPPEDICMPS);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800116
117 if (sk->sk_state == DCCP_CLOSED)
118 goto out;
119
Wei Yongjune0bcfb02008-07-26 11:59:10 +0100120 dp = dccp_sk(sk);
121 seq = dccp_hdr_seq(dh);
122 if ((1 << sk->sk_state) & ~(DCCPF_REQUESTING | DCCPF_LISTEN) &&
123 !between48(seq, dp->dccps_awl, dp->dccps_awh)) {
124 NET_INC_STATS_BH(net, LINUX_MIB_OUTOFWINDOWICMPS);
125 goto out;
126 }
127
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800128 np = inet6_sk(sk);
129
130 if (type == ICMPV6_PKT_TOOBIG) {
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800131 struct dst_entry *dst = NULL;
132
133 if (sock_owned_by_user(sk))
134 goto out;
135 if ((1 << sk->sk_state) & (DCCPF_LISTEN | DCCPF_CLOSED))
136 goto out;
137
138 /* icmp should have updated the destination cache entry */
139 dst = __sk_dst_check(sk, np->dst_cookie);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800140 if (dst == NULL) {
141 struct inet_sock *inet = inet_sk(sk);
142 struct flowi fl;
143
144 /* BUGGG_FUTURE: Again, it is not clear how
145 to handle rthdr case. Ignore this complexity
146 for now.
147 */
148 memset(&fl, 0, sizeof(fl));
149 fl.proto = IPPROTO_DCCP;
150 ipv6_addr_copy(&fl.fl6_dst, &np->daddr);
151 ipv6_addr_copy(&fl.fl6_src, &np->saddr);
152 fl.oif = sk->sk_bound_dev_if;
153 fl.fl_ip_dport = inet->dport;
154 fl.fl_ip_sport = inet->sport;
Venkat Yekkiralabeb8d132006-08-04 23:12:42 -0700155 security_sk_classify_flow(sk, &fl);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800156
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800157 err = ip6_dst_lookup(sk, &dst, &fl);
158 if (err) {
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800159 sk->sk_err_soft = -err;
160 goto out;
161 }
162
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800163 err = xfrm_lookup(&dst, &fl, sk, 0);
164 if (err < 0) {
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800165 sk->sk_err_soft = -err;
166 goto out;
167 }
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800168 } else
169 dst_hold(dst);
170
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -0800171 if (inet_csk(sk)->icsk_pmtu_cookie > dst_mtu(dst)) {
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800172 dccp_sync_mss(sk, dst_mtu(dst));
173 } /* else let the usual retransmit timer handle it */
174 dst_release(dst);
175 goto out;
176 }
177
178 icmpv6_err_convert(type, code, &err);
179
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800180 /* Might be for an request_sock */
181 switch (sk->sk_state) {
182 struct request_sock *req, **prev;
183 case DCCP_LISTEN:
184 if (sock_owned_by_user(sk))
185 goto out;
186
187 req = inet6_csk_search_req(sk, &prev, dh->dccph_dport,
188 &hdr->daddr, &hdr->saddr,
189 inet6_iif(skb));
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800190 if (req == NULL)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800191 goto out;
192
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800193 /*
194 * ICMPs are not backlogged, hence we cannot get an established
195 * socket here.
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800196 */
Ilpo Järvinen547b7922008-07-25 21:43:18 -0700197 WARN_ON(req->sk != NULL);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800198
199 if (seq != dccp_rsk(req)->dreq_iss) {
Pavel Emelyanovde0744a2008-07-16 20:31:16 -0700200 NET_INC_STATS_BH(net, LINUX_MIB_OUTOFWINDOWICMPS);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800201 goto out;
202 }
203
204 inet_csk_reqsk_queue_drop(sk, req, prev);
205 goto out;
206
207 case DCCP_REQUESTING:
208 case DCCP_RESPOND: /* Cannot happen.
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800209 It can, it SYNs are crossed. --ANK */
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800210 if (!sock_owned_by_user(sk)) {
211 DCCP_INC_STATS_BH(DCCP_MIB_ATTEMPTFAILS);
212 sk->sk_err = err;
213 /*
214 * Wake people up to see the error
215 * (see connect in sock.c)
216 */
217 sk->sk_error_report(sk);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800218 dccp_done(sk);
219 } else
220 sk->sk_err_soft = err;
221 goto out;
222 }
223
224 if (!sock_owned_by_user(sk) && np->recverr) {
225 sk->sk_err = err;
226 sk->sk_error_report(sk);
227 } else
228 sk->sk_err_soft = err;
229
230out:
231 bh_unlock_sock(sk);
232 sock_put(sk);
233}
234
235
Denis V. Lunevfd80eb92008-02-29 11:43:03 -0800236static int dccp_v6_send_response(struct sock *sk, struct request_sock *req)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800237{
238 struct inet6_request_sock *ireq6 = inet6_rsk(req);
239 struct ipv6_pinfo *np = inet6_sk(sk);
240 struct sk_buff *skb;
241 struct ipv6_txoptions *opt = NULL;
242 struct in6_addr *final_p = NULL, final;
243 struct flowi fl;
244 int err = -1;
Denis V. Lunevfd80eb92008-02-29 11:43:03 -0800245 struct dst_entry *dst;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800246
247 memset(&fl, 0, sizeof(fl));
248 fl.proto = IPPROTO_DCCP;
249 ipv6_addr_copy(&fl.fl6_dst, &ireq6->rmt_addr);
250 ipv6_addr_copy(&fl.fl6_src, &ireq6->loc_addr);
251 fl.fl6_flowlabel = 0;
252 fl.oif = ireq6->iif;
253 fl.fl_ip_dport = inet_rsk(req)->rmt_port;
254 fl.fl_ip_sport = inet_sk(sk)->sport;
Venkat Yekkirala4237c752006-07-24 23:32:50 -0700255 security_req_classify_flow(req, &fl);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800256
Denis V. Lunevfd80eb92008-02-29 11:43:03 -0800257 opt = np->opt;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800258
Denis V. Lunevfd80eb92008-02-29 11:43:03 -0800259 if (opt != NULL && opt->srcrt != NULL) {
260 const struct rt0_hdr *rt0 = (struct rt0_hdr *)opt->srcrt;
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800261
Denis V. Lunevfd80eb92008-02-29 11:43:03 -0800262 ipv6_addr_copy(&final, &fl.fl6_dst);
263 ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
264 final_p = &final;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800265 }
266
Denis V. Lunevfd80eb92008-02-29 11:43:03 -0800267 err = ip6_dst_lookup(sk, &dst, &fl);
268 if (err)
269 goto done;
270
271 if (final_p)
272 ipv6_addr_copy(&fl.fl6_dst, final_p);
273
274 err = xfrm_lookup(&dst, &fl, sk, 0);
275 if (err < 0)
276 goto done;
277
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800278 skb = dccp_make_response(sk, dst, req);
279 if (skb != NULL) {
280 struct dccp_hdr *dh = dccp_hdr(skb);
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800281
Gerrit Renker6f4e5ff2006-11-10 17:43:06 -0200282 dh->dccph_checksum = dccp_v6_csum_finish(skb,
283 &ireq6->loc_addr,
284 &ireq6->rmt_addr);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800285 ipv6_addr_copy(&fl.fl6_dst, &ireq6->rmt_addr);
286 err = ip6_xmit(sk, skb, &fl, opt, 0);
Gerrit Renkerb9df3cb2006-11-14 11:21:36 -0200287 err = net_xmit_eval(err);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800288 }
289
290done:
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800291 if (opt != NULL && opt != np->opt)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800292 sock_kfree_s(sk, opt, opt->tot_len);
David S. Miller0cbd7822006-01-31 17:53:37 -0800293 dst_release(dst);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800294 return err;
295}
296
297static void dccp_v6_reqsk_destructor(struct request_sock *req)
298{
299 if (inet6_rsk(req)->pktopts != NULL)
300 kfree_skb(inet6_rsk(req)->pktopts);
301}
302
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800303static void dccp_v6_ctl_send_reset(struct sock *sk, struct sk_buff *rxskb)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800304{
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700305 struct ipv6hdr *rxip6h;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800306 struct sk_buff *skb;
307 struct flowi fl;
Pavel Emelyanov334527d2008-04-13 22:32:45 -0700308 struct net *net = dev_net(rxskb->dst->dev);
309 struct sock *ctl_sk = net->dccp.v6_ctl_sk;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800310
Gerrit Renkere356d372007-09-26 14:35:19 -0300311 if (dccp_hdr(rxskb)->dccph_type == DCCP_PKT_RESET)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800312 return;
313
314 if (!ipv6_unicast_destination(rxskb))
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800315 return;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800316
Pavel Emelyanov02047742008-04-13 22:32:25 -0700317 skb = dccp_ctl_make_reset(ctl_sk, rxskb);
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800318 if (skb == NULL)
Arnaldo Carvalho de Melo8109b022006-12-10 16:01:18 -0200319 return;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800320
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700321 rxip6h = ipv6_hdr(rxskb);
Gerrit Renkere356d372007-09-26 14:35:19 -0300322 dccp_hdr(skb)->dccph_checksum = dccp_v6_csum_finish(skb, &rxip6h->saddr,
323 &rxip6h->daddr);
Gerrit Renker6f4e5ff2006-11-10 17:43:06 -0200324
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800325 memset(&fl, 0, sizeof(fl));
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700326 ipv6_addr_copy(&fl.fl6_dst, &rxip6h->saddr);
327 ipv6_addr_copy(&fl.fl6_src, &rxip6h->daddr);
Gerrit Renker6f4e5ff2006-11-10 17:43:06 -0200328
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800329 fl.proto = IPPROTO_DCCP;
330 fl.oif = inet6_iif(rxskb);
Gerrit Renkere356d372007-09-26 14:35:19 -0300331 fl.fl_ip_dport = dccp_hdr(skb)->dccph_dport;
332 fl.fl_ip_sport = dccp_hdr(skb)->dccph_sport;
Venkat Yekkiralabeb8d132006-08-04 23:12:42 -0700333 security_skb_classify_flow(rxskb, &fl);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800334
335 /* sk = NULL, but it is safe for now. RST socket required. */
Pavel Emelyanov02047742008-04-13 22:32:25 -0700336 if (!ip6_dst_lookup(ctl_sk, &skb->dst, &fl)) {
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800337 if (xfrm_lookup(&skb->dst, &fl, NULL, 0) >= 0) {
Pavel Emelyanov02047742008-04-13 22:32:25 -0700338 ip6_xmit(ctl_sk, skb, &fl, NULL, 0);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800339 DCCP_INC_STATS_BH(DCCP_MIB_OUTSEGS);
340 DCCP_INC_STATS_BH(DCCP_MIB_OUTRSTS);
341 return;
342 }
343 }
344
345 kfree_skb(skb);
346}
347
Gerrit Renker73c9e022006-11-10 13:01:31 -0200348static struct request_sock_ops dccp6_request_sock_ops = {
349 .family = AF_INET6,
350 .obj_size = sizeof(struct dccp6_request_sock),
351 .rtx_syn_ack = dccp_v6_send_response,
352 .send_ack = dccp_reqsk_send_ack,
353 .destructor = dccp_v6_reqsk_destructor,
354 .send_reset = dccp_v6_ctl_send_reset,
355};
356
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800357static struct sock *dccp_v6_hnd_req(struct sock *sk,struct sk_buff *skb)
358{
359 const struct dccp_hdr *dh = dccp_hdr(skb);
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700360 const struct ipv6hdr *iph = ipv6_hdr(skb);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800361 struct sock *nsk;
362 struct request_sock **prev;
363 /* Find possible connection requests. */
364 struct request_sock *req = inet6_csk_search_req(sk, &prev,
365 dh->dccph_sport,
366 &iph->saddr,
367 &iph->daddr,
368 inet6_iif(skb));
369 if (req != NULL)
370 return dccp_check_req(sk, skb, req, prev);
371
Pavel Emelyanov671a1c72008-04-13 22:33:06 -0700372 nsk = __inet6_lookup_established(sock_net(sk), &dccp_hashinfo,
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800373 &iph->saddr, dh->dccph_sport,
374 &iph->daddr, ntohs(dh->dccph_dport),
375 inet6_iif(skb));
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800376 if (nsk != NULL) {
377 if (nsk->sk_state != DCCP_TIME_WAIT) {
378 bh_lock_sock(nsk);
379 return nsk;
380 }
YOSHIFUJI Hideaki9469c7b2006-10-10 19:41:46 -0700381 inet_twsk_put(inet_twsk(nsk));
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800382 return NULL;
383 }
384
385 return sk;
386}
387
388static int dccp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
389{
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800390 struct request_sock *req;
391 struct dccp_request_sock *dreq;
392 struct inet6_request_sock *ireq6;
393 struct ipv6_pinfo *np = inet6_sk(sk);
Arnaldo Carvalho de Melo8109b022006-12-10 16:01:18 -0200394 const __be32 service = dccp_hdr_request(skb)->dccph_req_service;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800395 struct dccp_skb_cb *dcb = DCCP_SKB_CB(skb);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800396
397 if (skb->protocol == htons(ETH_P_IP))
398 return dccp_v4_conn_request(sk, skb);
399
400 if (!ipv6_unicast_destination(skb))
Gerrit Renker4a5409a2007-10-04 14:52:28 -0700401 return 0; /* discard, don't send a reset here */
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800402
403 if (dccp_bad_service_code(sk, service)) {
Gerrit Renker4a5409a2007-10-04 14:52:28 -0700404 dcb->dccpd_reset_code = DCCP_RESET_CODE_BAD_SERVICE_CODE;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800405 goto drop;
Arnaldo Carvalho de Melo8109b022006-12-10 16:01:18 -0200406 }
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800407 /*
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800408 * There are no SYN attacks on IPv6, yet...
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800409 */
Gerrit Renker4a5409a2007-10-04 14:52:28 -0700410 dcb->dccpd_reset_code = DCCP_RESET_CODE_TOO_BUSY;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800411 if (inet_csk_reqsk_queue_is_full(sk))
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800412 goto drop;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800413
414 if (sk_acceptq_is_full(sk) && inet_csk_reqsk_queue_young(sk) > 1)
415 goto drop;
416
Gerrit Renker82709532006-10-11 16:26:54 +0100417 req = inet6_reqsk_alloc(&dccp6_request_sock_ops);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800418 if (req == NULL)
419 goto drop;
420
Gerrit Renkercf557922006-11-10 16:08:37 -0200421 dccp_reqsk_init(req, skb);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800422
Gerrit Renker8b819412007-12-13 12:29:24 -0200423 dreq = dccp_rsk(req);
424 if (dccp_parse_options(sk, dreq, skb))
425 goto drop_and_free;
426
Venkat Yekkirala4237c752006-07-24 23:32:50 -0700427 if (security_inet_conn_request(sk, skb, req))
428 goto drop_and_free;
429
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800430 ireq6 = inet6_rsk(req);
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700431 ipv6_addr_copy(&ireq6->rmt_addr, &ipv6_hdr(skb)->saddr);
432 ipv6_addr_copy(&ireq6->loc_addr, &ipv6_hdr(skb)->daddr);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800433
434 if (ipv6_opt_accepted(sk, skb) ||
435 np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo ||
436 np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim) {
437 atomic_inc(&skb->users);
438 ireq6->pktopts = skb;
439 }
440 ireq6->iif = sk->sk_bound_dev_if;
441
442 /* So that link locals have meaning */
443 if (!sk->sk_bound_dev_if &&
444 ipv6_addr_type(&ireq6->rmt_addr) & IPV6_ADDR_LINKLOCAL)
445 ireq6->iif = inet6_iif(skb);
446
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800447 /*
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800448 * Step 3: Process LISTEN state
449 *
Gerrit Renkerd83ca5a2006-11-10 16:29:14 -0200450 * Set S.ISR, S.GSR, S.SWL, S.SWH from packet or Init Cookie
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800451 *
Gerrit Renkerd83ca5a2006-11-10 16:29:14 -0200452 * In fact we defer setting S.GSR, S.SWL, S.SWH to
453 * dccp_create_openreq_child.
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800454 */
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800455 dreq->dreq_isr = dcb->dccpd_seq;
Gerrit Renker865e9022006-11-13 13:31:50 -0200456 dreq->dreq_iss = dccp_v6_init_sequence(skb);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800457 dreq->dreq_service = service;
458
Denis V. Lunevfd80eb92008-02-29 11:43:03 -0800459 if (dccp_v6_send_response(sk, req))
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800460 goto drop_and_free;
461
462 inet6_csk_reqsk_queue_hash_add(sk, req, DCCP_TIMEOUT_INIT);
463 return 0;
464
465drop_and_free:
466 reqsk_free(req);
467drop:
468 DCCP_INC_STATS_BH(DCCP_MIB_ATTEMPTFAILS);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800469 return -1;
470}
471
472static struct sock *dccp_v6_request_recv_sock(struct sock *sk,
473 struct sk_buff *skb,
474 struct request_sock *req,
475 struct dst_entry *dst)
476{
477 struct inet6_request_sock *ireq6 = inet6_rsk(req);
478 struct ipv6_pinfo *newnp, *np = inet6_sk(sk);
479 struct inet_sock *newinet;
480 struct dccp_sock *newdp;
481 struct dccp6_sock *newdp6;
482 struct sock *newsk;
483 struct ipv6_txoptions *opt;
484
485 if (skb->protocol == htons(ETH_P_IP)) {
486 /*
487 * v6 mapped
488 */
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800489 newsk = dccp_v4_request_recv_sock(sk, skb, req, dst);
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800490 if (newsk == NULL)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800491 return NULL;
492
493 newdp6 = (struct dccp6_sock *)newsk;
494 newdp = dccp_sk(newsk);
495 newinet = inet_sk(newsk);
496 newinet->pinet6 = &newdp6->inet6;
497 newnp = inet6_sk(newsk);
498
499 memcpy(newnp, np, sizeof(struct ipv6_pinfo));
500
501 ipv6_addr_set(&newnp->daddr, 0, 0, htonl(0x0000FFFF),
502 newinet->daddr);
503
504 ipv6_addr_set(&newnp->saddr, 0, 0, htonl(0x0000FFFF),
505 newinet->saddr);
506
507 ipv6_addr_copy(&newnp->rcv_saddr, &newnp->saddr);
508
509 inet_csk(newsk)->icsk_af_ops = &dccp_ipv6_mapped;
510 newsk->sk_backlog_rcv = dccp_v4_do_rcv;
511 newnp->pktoptions = NULL;
512 newnp->opt = NULL;
513 newnp->mcast_oif = inet6_iif(skb);
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700514 newnp->mcast_hops = ipv6_hdr(skb)->hop_limit;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800515
516 /*
517 * No need to charge this sock to the relevant IPv6 refcnt debug socks count
518 * here, dccp_create_openreq_child now does this for us, see the comment in
519 * that function for the gory details. -acme
520 */
521
522 /* It is tricky place. Until this moment IPv4 tcp
523 worked with IPv6 icsk.icsk_af_ops.
524 Sync it now.
525 */
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -0800526 dccp_sync_mss(newsk, inet_csk(newsk)->icsk_pmtu_cookie);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800527
528 return newsk;
529 }
530
531 opt = np->opt;
532
533 if (sk_acceptq_is_full(sk))
534 goto out_overflow;
535
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800536 if (dst == NULL) {
537 struct in6_addr *final_p = NULL, final;
538 struct flowi fl;
539
540 memset(&fl, 0, sizeof(fl));
541 fl.proto = IPPROTO_DCCP;
542 ipv6_addr_copy(&fl.fl6_dst, &ireq6->rmt_addr);
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800543 if (opt != NULL && opt->srcrt != NULL) {
544 const struct rt0_hdr *rt0 = (struct rt0_hdr *)opt->srcrt;
545
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800546 ipv6_addr_copy(&final, &fl.fl6_dst);
547 ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
548 final_p = &final;
549 }
550 ipv6_addr_copy(&fl.fl6_src, &ireq6->loc_addr);
551 fl.oif = sk->sk_bound_dev_if;
552 fl.fl_ip_dport = inet_rsk(req)->rmt_port;
553 fl.fl_ip_sport = inet_sk(sk)->sport;
Venkat Yekkiralabeb8d132006-08-04 23:12:42 -0700554 security_sk_classify_flow(sk, &fl);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800555
556 if (ip6_dst_lookup(sk, &dst, &fl))
557 goto out;
558
559 if (final_p)
560 ipv6_addr_copy(&fl.fl6_dst, final_p);
561
562 if ((xfrm_lookup(&dst, &fl, sk, 0)) < 0)
563 goto out;
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800564 }
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800565
566 newsk = dccp_create_openreq_child(sk, req, skb);
567 if (newsk == NULL)
568 goto out;
569
570 /*
571 * No need to charge this sock to the relevant IPv6 refcnt debug socks
572 * count here, dccp_create_openreq_child now does this for us, see the
573 * comment in that function for the gory details. -acme
574 */
575
YOSHIFUJI Hideaki8e1ef0a2006-08-29 17:15:09 -0700576 __ip6_dst_store(newsk, dst, NULL, NULL);
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800577 newsk->sk_route_caps = dst->dev->features & ~(NETIF_F_IP_CSUM |
578 NETIF_F_TSO);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800579 newdp6 = (struct dccp6_sock *)newsk;
580 newinet = inet_sk(newsk);
581 newinet->pinet6 = &newdp6->inet6;
582 newdp = dccp_sk(newsk);
583 newnp = inet6_sk(newsk);
584
585 memcpy(newnp, np, sizeof(struct ipv6_pinfo));
586
587 ipv6_addr_copy(&newnp->daddr, &ireq6->rmt_addr);
588 ipv6_addr_copy(&newnp->saddr, &ireq6->loc_addr);
589 ipv6_addr_copy(&newnp->rcv_saddr, &ireq6->loc_addr);
590 newsk->sk_bound_dev_if = ireq6->iif;
591
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800592 /* Now IPv6 options...
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800593
594 First: no IPv4 options.
595 */
596 newinet->opt = NULL;
597
598 /* Clone RX bits */
599 newnp->rxopt.all = np->rxopt.all;
600
601 /* Clone pktoptions received with SYN */
602 newnp->pktoptions = NULL;
603 if (ireq6->pktopts != NULL) {
604 newnp->pktoptions = skb_clone(ireq6->pktopts, GFP_ATOMIC);
605 kfree_skb(ireq6->pktopts);
606 ireq6->pktopts = NULL;
607 if (newnp->pktoptions)
608 skb_set_owner_r(newnp->pktoptions, newsk);
609 }
610 newnp->opt = NULL;
611 newnp->mcast_oif = inet6_iif(skb);
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700612 newnp->mcast_hops = ipv6_hdr(skb)->hop_limit;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800613
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800614 /*
615 * Clone native IPv6 options from listening socket (if any)
616 *
617 * Yes, keeping reference count would be much more clever, but we make
618 * one more one thing there: reattach optmem to newsk.
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800619 */
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800620 if (opt != NULL) {
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800621 newnp->opt = ipv6_dup_options(newsk, opt);
622 if (opt != np->opt)
623 sock_kfree_s(sk, opt, opt->tot_len);
624 }
625
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -0800626 inet_csk(newsk)->icsk_ext_hdr_len = 0;
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800627 if (newnp->opt != NULL)
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -0800628 inet_csk(newsk)->icsk_ext_hdr_len = (newnp->opt->opt_nflen +
629 newnp->opt->opt_flen);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800630
631 dccp_sync_mss(newsk, dst_mtu(dst));
632
633 newinet->daddr = newinet->saddr = newinet->rcv_saddr = LOOPBACK4_IPV6;
634
Arnaldo Carvalho de Meloab1e0a12008-02-03 04:06:04 -0800635 __inet6_hash(newsk);
Pavel Emelyanove56d8b82008-04-17 23:17:34 -0700636 __inet_inherit_port(sk, newsk);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800637
638 return newsk;
639
640out_overflow:
Pavel Emelyanovde0744a2008-07-16 20:31:16 -0700641 NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENOVERFLOWS);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800642out:
Pavel Emelyanovde0744a2008-07-16 20:31:16 -0700643 NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENDROPS);
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800644 if (opt != NULL && opt != np->opt)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800645 sock_kfree_s(sk, opt, opt->tot_len);
646 dst_release(dst);
647 return NULL;
648}
649
650/* The socket must have it's spinlock held when we get
651 * here.
652 *
653 * We have a potential double-lock case here, so even when
654 * doing backlog processing we use the BH locking scheme.
655 * This is because we cannot sleep with the original spinlock
656 * held.
657 */
658static int dccp_v6_do_rcv(struct sock *sk, struct sk_buff *skb)
659{
660 struct ipv6_pinfo *np = inet6_sk(sk);
661 struct sk_buff *opt_skb = NULL;
662
663 /* Imagine: socket is IPv6. IPv4 packet arrives,
664 goes to IPv4 receive handler and backlogged.
665 From backlog it always goes here. Kerboom...
666 Fortunately, dccp_rcv_established and rcv_established
667 handle them correctly, but it is not case with
668 dccp_v6_hnd_req and dccp_v6_ctl_send_reset(). --ANK
669 */
670
671 if (skb->protocol == htons(ETH_P_IP))
672 return dccp_v4_do_rcv(sk, skb);
673
Dmitry Mishinfda9ef52006-08-31 15:28:39 -0700674 if (sk_filter(sk, skb))
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800675 goto discard;
676
677 /*
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800678 * socket locking is here for SMP purposes as backlog rcv is currently
679 * called with bh processing disabled.
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800680 */
681
682 /* Do Stevens' IPV6_PKTOPTIONS.
683
684 Yes, guys, it is the only place in our code, where we
685 may make it not affecting IPv4.
686 The rest of code is protocol independent,
687 and I do not like idea to uglify IPv4.
688
689 Actually, all the idea behind IPV6_PKTOPTIONS
690 looks not very well thought. For now we latch
691 options, received in the last packet, enqueued
692 by tcp. Feel free to propose better solution.
YOSHIFUJI Hideakic9eaf172007-02-09 23:24:38 +0900693 --ANK (980728)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800694 */
695 if (np->rxopt.all)
Gerrit Renker89e7e572006-11-10 11:13:33 -0200696 /*
697 * FIXME: Add handling of IPV6_PKTOPTIONS skb. See the comments below
698 * (wrt ipv6_pktopions) and net/ipv6/tcp_ipv6.c for an example.
699 */
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800700 opt_skb = skb_clone(skb, GFP_ATOMIC);
701
702 if (sk->sk_state == DCCP_OPEN) { /* Fast path */
703 if (dccp_rcv_established(sk, skb, dccp_hdr(skb), skb->len))
704 goto reset;
David S. Millerfd169f12006-10-20 19:44:17 -0700705 if (opt_skb) {
Gerrit Renker89e7e572006-11-10 11:13:33 -0200706 /* XXX This is where we would goto ipv6_pktoptions. */
David S. Millerfd169f12006-10-20 19:44:17 -0700707 __kfree_skb(opt_skb);
708 }
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800709 return 0;
710 }
711
Gerrit Renkerd83ca5a2006-11-10 16:29:14 -0200712 /*
713 * Step 3: Process LISTEN state
714 * If S.state == LISTEN,
715 * If P.type == Request or P contains a valid Init Cookie option,
716 * (* Must scan the packet's options to check for Init
717 * Cookies. Only Init Cookies are processed here,
718 * however; other options are processed in Step 8. This
719 * scan need only be performed if the endpoint uses Init
720 * Cookies *)
721 * (* Generate a new socket and switch to that socket *)
722 * Set S := new socket for this port pair
723 * S.state = RESPOND
724 * Choose S.ISS (initial seqno) or set from Init Cookies
725 * Initialize S.GAR := S.ISS
726 * Set S.ISR, S.GSR, S.SWL, S.SWH from packet or Init Cookies
727 * Continue with S.state == RESPOND
728 * (* A Response packet will be generated in Step 11 *)
729 * Otherwise,
730 * Generate Reset(No Connection) unless P.type == Reset
731 * Drop packet and return
732 *
733 * NOTE: the check for the packet types is done in
734 * dccp_rcv_state_process
735 */
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800736 if (sk->sk_state == DCCP_LISTEN) {
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800737 struct sock *nsk = dccp_v6_hnd_req(sk, skb);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800738
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800739 if (nsk == NULL)
740 goto discard;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800741 /*
742 * Queue it on the new socket if the new socket is active,
743 * otherwise we just shortcircuit this and continue with
744 * the new socket..
745 */
Arnaldo Carvalho de Melo8109b022006-12-10 16:01:18 -0200746 if (nsk != sk) {
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800747 if (dccp_child_process(sk, nsk, skb))
748 goto reset;
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800749 if (opt_skb != NULL)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800750 __kfree_skb(opt_skb);
751 return 0;
752 }
753 }
754
755 if (dccp_rcv_state_process(sk, skb, dccp_hdr(skb), skb->len))
756 goto reset;
David S. Millerfd169f12006-10-20 19:44:17 -0700757 if (opt_skb) {
Gerrit Renker89e7e572006-11-10 11:13:33 -0200758 /* XXX This is where we would goto ipv6_pktoptions. */
David S. Millerfd169f12006-10-20 19:44:17 -0700759 __kfree_skb(opt_skb);
760 }
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800761 return 0;
762
763reset:
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800764 dccp_v6_ctl_send_reset(sk, skb);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800765discard:
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800766 if (opt_skb != NULL)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800767 __kfree_skb(opt_skb);
768 kfree_skb(skb);
769 return 0;
770}
771
Herbert Xue5bbef22007-10-15 12:50:28 -0700772static int dccp_v6_rcv(struct sk_buff *skb)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800773{
774 const struct dccp_hdr *dh;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800775 struct sock *sk;
Gerrit Renker6f4e5ff2006-11-10 17:43:06 -0200776 int min_cov;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800777
Gerrit Renker6f4e5ff2006-11-10 17:43:06 -0200778 /* Step 1: Check header basics */
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800779
780 if (dccp_invalid_packet(skb))
781 goto discard_it;
782
Gerrit Renker6f4e5ff2006-11-10 17:43:06 -0200783 /* Step 1: If header checksum is incorrect, drop packet and return. */
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700784 if (dccp_v6_csum_finish(skb, &ipv6_hdr(skb)->saddr,
785 &ipv6_hdr(skb)->daddr)) {
Gerrit Renker59348b12006-11-20 18:39:23 -0200786 DCCP_WARN("dropped packet with invalid checksum\n");
Gerrit Renker6f4e5ff2006-11-10 17:43:06 -0200787 goto discard_it;
788 }
789
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800790 dh = dccp_hdr(skb);
791
Gerrit Renkerfde20102007-10-24 10:12:09 -0200792 DCCP_SKB_CB(skb)->dccpd_seq = dccp_hdr_seq(dh);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800793 DCCP_SKB_CB(skb)->dccpd_type = dh->dccph_type;
794
795 if (dccp_packet_without_ack(skb))
796 DCCP_SKB_CB(skb)->dccpd_ack_seq = DCCP_PKT_WITHOUT_ACK_SEQ;
797 else
798 DCCP_SKB_CB(skb)->dccpd_ack_seq = dccp_hdr_ack_seq(skb);
799
800 /* Step 2:
Arnaldo Carvalho de Melo8109b022006-12-10 16:01:18 -0200801 * Look up flow ID in table and get corresponding socket */
Pavel Emelyanov671a1c72008-04-13 22:33:06 -0700802 sk = __inet6_lookup(dev_net(skb->dst->dev), &dccp_hashinfo,
803 &ipv6_hdr(skb)->saddr, dh->dccph_sport,
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700804 &ipv6_hdr(skb)->daddr, ntohs(dh->dccph_dport),
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800805 inet6_iif(skb));
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800806 /*
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800807 * Step 2:
Arnaldo Carvalho de Melo8109b022006-12-10 16:01:18 -0200808 * If no socket ...
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800809 */
Gerrit Renkerd23c7102006-11-10 11:46:34 -0200810 if (sk == NULL) {
811 dccp_pr_debug("failed to look up flow ID in table and "
812 "get corresponding socket\n");
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800813 goto no_dccp_socket;
Gerrit Renkerd23c7102006-11-10 11:46:34 -0200814 }
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800815
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800816 /*
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800817 * Step 2:
Arnaldo Carvalho de Melo8109b022006-12-10 16:01:18 -0200818 * ... or S.state == TIMEWAIT,
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800819 * Generate Reset(No Connection) unless P.type == Reset
820 * Drop packet and return
821 */
Gerrit Renkerd23c7102006-11-10 11:46:34 -0200822 if (sk->sk_state == DCCP_TIME_WAIT) {
823 dccp_pr_debug("sk->sk_state == DCCP_TIME_WAIT: do_time_wait\n");
824 inet_twsk_put(inet_twsk(sk));
825 goto no_dccp_socket;
826 }
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800827
Gerrit Renker6f4e5ff2006-11-10 17:43:06 -0200828 /*
829 * RFC 4340, sec. 9.2.1: Minimum Checksum Coverage
Arnaldo Carvalho de Melo8109b022006-12-10 16:01:18 -0200830 * o if MinCsCov = 0, only packets with CsCov = 0 are accepted
831 * o if MinCsCov > 0, also accept packets with CsCov >= MinCsCov
Gerrit Renker6f4e5ff2006-11-10 17:43:06 -0200832 */
833 min_cov = dccp_sk(sk)->dccps_pcrlen;
834 if (dh->dccph_cscov && (min_cov == 0 || dh->dccph_cscov < min_cov)) {
835 dccp_pr_debug("Packet CsCov %d does not satisfy MinCsCov %d\n",
836 dh->dccph_cscov, min_cov);
837 /* FIXME: send Data Dropped option (see also dccp_v4_rcv) */
838 goto discard_and_relse;
839 }
840
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800841 if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb))
842 goto discard_and_relse;
843
Arnaldo Carvalho de Melo58a5a7b2006-11-16 14:06:06 -0200844 return sk_receive_skb(sk, skb, 1) ? -1 : 0;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800845
846no_dccp_socket:
847 if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb))
848 goto discard_it;
849 /*
850 * Step 2:
Arnaldo Carvalho de Melo8109b022006-12-10 16:01:18 -0200851 * If no socket ...
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800852 * Generate Reset(No Connection) unless P.type == Reset
853 * Drop packet and return
854 */
855 if (dh->dccph_type != DCCP_PKT_RESET) {
856 DCCP_SKB_CB(skb)->dccpd_reset_code =
857 DCCP_RESET_CODE_NO_CONNECTION;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800858 dccp_v6_ctl_send_reset(sk, skb);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800859 }
Gerrit Renkerd23c7102006-11-10 11:46:34 -0200860
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800861discard_it:
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800862 kfree_skb(skb);
863 return 0;
864
865discard_and_relse:
866 sock_put(sk);
867 goto discard_it;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800868}
869
Gerrit Renker73c9e022006-11-10 13:01:31 -0200870static int dccp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
871 int addr_len)
872{
873 struct sockaddr_in6 *usin = (struct sockaddr_in6 *)uaddr;
874 struct inet_connection_sock *icsk = inet_csk(sk);
875 struct inet_sock *inet = inet_sk(sk);
876 struct ipv6_pinfo *np = inet6_sk(sk);
877 struct dccp_sock *dp = dccp_sk(sk);
878 struct in6_addr *saddr = NULL, *final_p = NULL, final;
879 struct flowi fl;
880 struct dst_entry *dst;
881 int addr_type;
882 int err;
883
884 dp->dccps_role = DCCP_ROLE_CLIENT;
885
886 if (addr_len < SIN6_LEN_RFC2133)
887 return -EINVAL;
888
889 if (usin->sin6_family != AF_INET6)
890 return -EAFNOSUPPORT;
891
892 memset(&fl, 0, sizeof(fl));
893
894 if (np->sndflow) {
895 fl.fl6_flowlabel = usin->sin6_flowinfo & IPV6_FLOWINFO_MASK;
896 IP6_ECN_flow_init(fl.fl6_flowlabel);
897 if (fl.fl6_flowlabel & IPV6_FLOWLABEL_MASK) {
898 struct ip6_flowlabel *flowlabel;
899 flowlabel = fl6_sock_lookup(sk, fl.fl6_flowlabel);
900 if (flowlabel == NULL)
901 return -EINVAL;
902 ipv6_addr_copy(&usin->sin6_addr, &flowlabel->dst);
903 fl6_sock_release(flowlabel);
904 }
905 }
906 /*
907 * connect() to INADDR_ANY means loopback (BSD'ism).
908 */
909 if (ipv6_addr_any(&usin->sin6_addr))
910 usin->sin6_addr.s6_addr[15] = 1;
911
912 addr_type = ipv6_addr_type(&usin->sin6_addr);
913
914 if (addr_type & IPV6_ADDR_MULTICAST)
915 return -ENETUNREACH;
916
917 if (addr_type & IPV6_ADDR_LINKLOCAL) {
918 if (addr_len >= sizeof(struct sockaddr_in6) &&
919 usin->sin6_scope_id) {
920 /* If interface is set while binding, indices
921 * must coincide.
922 */
923 if (sk->sk_bound_dev_if &&
924 sk->sk_bound_dev_if != usin->sin6_scope_id)
925 return -EINVAL;
926
927 sk->sk_bound_dev_if = usin->sin6_scope_id;
928 }
929
930 /* Connect to link-local address requires an interface */
931 if (!sk->sk_bound_dev_if)
932 return -EINVAL;
933 }
934
935 ipv6_addr_copy(&np->daddr, &usin->sin6_addr);
936 np->flow_label = fl.fl6_flowlabel;
937
938 /*
939 * DCCP over IPv4
940 */
941 if (addr_type == IPV6_ADDR_MAPPED) {
942 u32 exthdrlen = icsk->icsk_ext_hdr_len;
943 struct sockaddr_in sin;
944
945 SOCK_DEBUG(sk, "connect: ipv4 mapped\n");
946
947 if (__ipv6_only_sock(sk))
948 return -ENETUNREACH;
949
950 sin.sin_family = AF_INET;
951 sin.sin_port = usin->sin6_port;
952 sin.sin_addr.s_addr = usin->sin6_addr.s6_addr32[3];
953
954 icsk->icsk_af_ops = &dccp_ipv6_mapped;
955 sk->sk_backlog_rcv = dccp_v4_do_rcv;
956
957 err = dccp_v4_connect(sk, (struct sockaddr *)&sin, sizeof(sin));
958 if (err) {
959 icsk->icsk_ext_hdr_len = exthdrlen;
960 icsk->icsk_af_ops = &dccp_ipv6_af_ops;
961 sk->sk_backlog_rcv = dccp_v6_do_rcv;
962 goto failure;
963 } else {
964 ipv6_addr_set(&np->saddr, 0, 0, htonl(0x0000FFFF),
965 inet->saddr);
966 ipv6_addr_set(&np->rcv_saddr, 0, 0, htonl(0x0000FFFF),
967 inet->rcv_saddr);
968 }
969
970 return err;
971 }
972
973 if (!ipv6_addr_any(&np->rcv_saddr))
974 saddr = &np->rcv_saddr;
975
976 fl.proto = IPPROTO_DCCP;
977 ipv6_addr_copy(&fl.fl6_dst, &np->daddr);
978 ipv6_addr_copy(&fl.fl6_src, saddr ? saddr : &np->saddr);
979 fl.oif = sk->sk_bound_dev_if;
980 fl.fl_ip_dport = usin->sin6_port;
981 fl.fl_ip_sport = inet->sport;
982 security_sk_classify_flow(sk, &fl);
983
984 if (np->opt != NULL && np->opt->srcrt != NULL) {
985 const struct rt0_hdr *rt0 = (struct rt0_hdr *)np->opt->srcrt;
986
987 ipv6_addr_copy(&final, &fl.fl6_dst);
988 ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
989 final_p = &final;
990 }
991
992 err = ip6_dst_lookup(sk, &dst, &fl);
993 if (err)
994 goto failure;
995
996 if (final_p)
997 ipv6_addr_copy(&fl.fl6_dst, final_p);
998
Herbert Xubb728452007-12-12 18:48:58 -0800999 err = __xfrm_lookup(&dst, &fl, sk, XFRM_LOOKUP_WAIT);
David S. Miller14e50e52007-05-24 18:17:54 -07001000 if (err < 0) {
1001 if (err == -EREMOTE)
1002 err = ip6_dst_blackhole(sk, &dst, &fl);
1003 if (err < 0)
1004 goto failure;
1005 }
Gerrit Renker73c9e022006-11-10 13:01:31 -02001006
1007 if (saddr == NULL) {
1008 saddr = &fl.fl6_src;
1009 ipv6_addr_copy(&np->rcv_saddr, saddr);
1010 }
1011
1012 /* set the source address */
1013 ipv6_addr_copy(&np->saddr, saddr);
1014 inet->rcv_saddr = LOOPBACK4_IPV6;
1015
1016 __ip6_dst_store(sk, dst, NULL, NULL);
1017
1018 icsk->icsk_ext_hdr_len = 0;
1019 if (np->opt != NULL)
1020 icsk->icsk_ext_hdr_len = (np->opt->opt_flen +
1021 np->opt->opt_nflen);
1022
1023 inet->dport = usin->sin6_port;
1024
1025 dccp_set_state(sk, DCCP_REQUESTING);
1026 err = inet6_hash_connect(&dccp_death_row, sk);
1027 if (err)
1028 goto late_failure;
Gerrit Renkerd7f73652006-11-13 13:34:38 -02001029
1030 dp->dccps_iss = secure_dccpv6_sequence_number(np->saddr.s6_addr32,
1031 np->daddr.s6_addr32,
1032 inet->sport, inet->dport);
Gerrit Renker73c9e022006-11-10 13:01:31 -02001033 err = dccp_connect(sk);
1034 if (err)
1035 goto late_failure;
1036
1037 return 0;
1038
1039late_failure:
1040 dccp_set_state(sk, DCCP_CLOSED);
1041 __sk_dst_reset(sk);
1042failure:
1043 inet->dport = 0;
1044 sk->sk_route_caps = 0;
1045 return err;
1046}
1047
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001048static struct inet_connection_sock_af_ops dccp_ipv6_af_ops = {
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001049 .queue_xmit = inet6_csk_xmit,
1050 .send_check = dccp_v6_send_check,
1051 .rebuild_header = inet6_sk_rebuild_header,
1052 .conn_request = dccp_v6_conn_request,
1053 .syn_recv_sock = dccp_v6_request_recv_sock,
1054 .net_header_len = sizeof(struct ipv6hdr),
1055 .setsockopt = ipv6_setsockopt,
1056 .getsockopt = ipv6_getsockopt,
1057 .addr2sockaddr = inet6_csk_addr2sockaddr,
1058 .sockaddr_len = sizeof(struct sockaddr_in6),
Arnaldo Carvalho de Meloab1e0a12008-02-03 04:06:04 -08001059 .bind_conflict = inet6_csk_bind_conflict,
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001060#ifdef CONFIG_COMPAT
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001061 .compat_setsockopt = compat_ipv6_setsockopt,
1062 .compat_getsockopt = compat_ipv6_getsockopt,
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001063#endif
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001064};
1065
1066/*
1067 * DCCP over IPv4 via INET6 API
1068 */
1069static struct inet_connection_sock_af_ops dccp_ipv6_mapped = {
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001070 .queue_xmit = ip_queue_xmit,
1071 .send_check = dccp_v4_send_check,
1072 .rebuild_header = inet_sk_rebuild_header,
1073 .conn_request = dccp_v6_conn_request,
1074 .syn_recv_sock = dccp_v6_request_recv_sock,
1075 .net_header_len = sizeof(struct iphdr),
1076 .setsockopt = ipv6_setsockopt,
1077 .getsockopt = ipv6_getsockopt,
1078 .addr2sockaddr = inet6_csk_addr2sockaddr,
1079 .sockaddr_len = sizeof(struct sockaddr_in6),
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001080#ifdef CONFIG_COMPAT
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001081 .compat_setsockopt = compat_ipv6_setsockopt,
1082 .compat_getsockopt = compat_ipv6_getsockopt,
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001083#endif
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001084};
1085
1086/* NOTE: A lot of things set to zero explicitly by call to
1087 * sk_alloc() so need not be done here.
1088 */
1089static int dccp_v6_init_sock(struct sock *sk)
1090{
Arnaldo Carvalho de Melo72478872006-03-20 22:00:37 -08001091 static __u8 dccp_v6_ctl_sock_initialized;
1092 int err = dccp_init_sock(sk, dccp_v6_ctl_sock_initialized);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001093
Arnaldo Carvalho de Melo72478872006-03-20 22:00:37 -08001094 if (err == 0) {
1095 if (unlikely(!dccp_v6_ctl_sock_initialized))
1096 dccp_v6_ctl_sock_initialized = 1;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001097 inet_csk(sk)->icsk_af_ops = &dccp_ipv6_af_ops;
Arnaldo Carvalho de Melo72478872006-03-20 22:00:37 -08001098 }
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001099
1100 return err;
1101}
1102
Brian Haley7d06b2e2008-06-14 17:04:49 -07001103static void dccp_v6_destroy_sock(struct sock *sk)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001104{
Arnaldo Carvalho de Melo3e0fadc2006-03-20 21:23:15 -08001105 dccp_destroy_sock(sk);
Brian Haley7d06b2e2008-06-14 17:04:49 -07001106 inet6_destroy_sock(sk);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001107}
1108
Gerrit Renker73c9e022006-11-10 13:01:31 -02001109static struct timewait_sock_ops dccp6_timewait_sock_ops = {
1110 .twsk_obj_size = sizeof(struct dccp6_timewait_sock),
1111};
1112
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001113static struct proto dccp_v6_prot = {
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001114 .name = "DCCPv6",
1115 .owner = THIS_MODULE,
1116 .close = dccp_close,
1117 .connect = dccp_v6_connect,
1118 .disconnect = dccp_disconnect,
1119 .ioctl = dccp_ioctl,
1120 .init = dccp_v6_init_sock,
1121 .setsockopt = dccp_setsockopt,
1122 .getsockopt = dccp_getsockopt,
1123 .sendmsg = dccp_sendmsg,
1124 .recvmsg = dccp_recvmsg,
1125 .backlog_rcv = dccp_v6_do_rcv,
1126 .hash = dccp_v6_hash,
Arnaldo Carvalho de Meloab1e0a12008-02-03 04:06:04 -08001127 .unhash = inet_unhash,
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001128 .accept = inet_csk_accept,
Arnaldo Carvalho de Meloab1e0a12008-02-03 04:06:04 -08001129 .get_port = inet_csk_get_port,
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001130 .shutdown = dccp_shutdown,
1131 .destroy = dccp_v6_destroy_sock,
1132 .orphan_count = &dccp_orphan_count,
1133 .max_header = MAX_DCCP_HEADER,
1134 .obj_size = sizeof(struct dccp6_sock),
1135 .rsk_prot = &dccp6_request_sock_ops,
1136 .twsk_prot = &dccp6_timewait_sock_ops,
Pavel Emelyanov39d8cda2008-03-22 16:50:58 -07001137 .h.hashinfo = &dccp_hashinfo,
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001138#ifdef CONFIG_COMPAT
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001139 .compat_setsockopt = compat_dccp_setsockopt,
1140 .compat_getsockopt = compat_dccp_getsockopt,
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001141#endif
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001142};
1143
1144static struct inet6_protocol dccp_v6_protocol = {
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -08001145 .handler = dccp_v6_rcv,
1146 .err_handler = dccp_v6_err,
1147 .flags = INET6_PROTO_NOPOLICY | INET6_PROTO_FINAL,
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001148};
1149
1150static struct proto_ops inet6_dccp_ops = {
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001151 .family = PF_INET6,
1152 .owner = THIS_MODULE,
1153 .release = inet6_release,
1154 .bind = inet6_bind,
1155 .connect = inet_stream_connect,
1156 .socketpair = sock_no_socketpair,
1157 .accept = inet_accept,
1158 .getname = inet6_getname,
1159 .poll = dccp_poll,
1160 .ioctl = inet6_ioctl,
1161 .listen = inet_dccp_listen,
1162 .shutdown = inet_shutdown,
1163 .setsockopt = sock_common_setsockopt,
1164 .getsockopt = sock_common_getsockopt,
1165 .sendmsg = inet_sendmsg,
1166 .recvmsg = sock_common_recvmsg,
1167 .mmap = sock_no_mmap,
1168 .sendpage = sock_no_sendpage,
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001169#ifdef CONFIG_COMPAT
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001170 .compat_setsockopt = compat_sock_common_setsockopt,
1171 .compat_getsockopt = compat_sock_common_getsockopt,
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001172#endif
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001173};
1174
1175static struct inet_protosw dccp_v6_protosw = {
1176 .type = SOCK_DCCP,
1177 .protocol = IPPROTO_DCCP,
1178 .prot = &dccp_v6_prot,
1179 .ops = &inet6_dccp_ops,
1180 .capability = -1,
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -08001181 .flags = INET_PROTOSW_ICSK,
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001182};
1183
Pavel Emelyanov8231bd22008-04-13 22:32:02 -07001184static int dccp_v6_init_net(struct net *net)
1185{
Pavel Emelyanov334527d2008-04-13 22:32:45 -07001186 int err;
1187
1188 err = inet_ctl_sock_create(&net->dccp.v6_ctl_sk, PF_INET6,
1189 SOCK_DCCP, IPPROTO_DCCP, net);
1190 return err;
Pavel Emelyanov8231bd22008-04-13 22:32:02 -07001191}
1192
1193static void dccp_v6_exit_net(struct net *net)
1194{
Pavel Emelyanov334527d2008-04-13 22:32:45 -07001195 inet_ctl_sock_destroy(net->dccp.v6_ctl_sk);
Pavel Emelyanov8231bd22008-04-13 22:32:02 -07001196}
1197
1198static struct pernet_operations dccp_v6_ops = {
1199 .init = dccp_v6_init_net,
1200 .exit = dccp_v6_exit_net,
1201};
1202
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001203static int __init dccp_v6_init(void)
1204{
1205 int err = proto_register(&dccp_v6_prot, 1);
1206
1207 if (err != 0)
1208 goto out;
1209
1210 err = inet6_add_protocol(&dccp_v6_protocol, IPPROTO_DCCP);
1211 if (err != 0)
1212 goto out_unregister_proto;
1213
1214 inet6_register_protosw(&dccp_v6_protosw);
Arnaldo Carvalho de Melo72478872006-03-20 22:00:37 -08001215
Pavel Emelyanov8231bd22008-04-13 22:32:02 -07001216 err = register_pernet_subsys(&dccp_v6_ops);
1217 if (err != 0)
1218 goto out_destroy_ctl_sock;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001219out:
1220 return err;
Pavel Emelyanov8231bd22008-04-13 22:32:02 -07001221
1222out_destroy_ctl_sock:
Arnaldo Carvalho de Melo72478872006-03-20 22:00:37 -08001223 inet6_del_protocol(&dccp_v6_protocol, IPPROTO_DCCP);
1224 inet6_unregister_protosw(&dccp_v6_protosw);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001225out_unregister_proto:
1226 proto_unregister(&dccp_v6_prot);
1227 goto out;
1228}
1229
1230static void __exit dccp_v6_exit(void)
1231{
Pavel Emelyanov8231bd22008-04-13 22:32:02 -07001232 unregister_pernet_subsys(&dccp_v6_ops);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001233 inet6_del_protocol(&dccp_v6_protocol, IPPROTO_DCCP);
1234 inet6_unregister_protosw(&dccp_v6_protosw);
1235 proto_unregister(&dccp_v6_prot);
1236}
1237
1238module_init(dccp_v6_init);
1239module_exit(dccp_v6_exit);
1240
1241/*
1242 * __stringify doesn't likes enums, so use SOCK_DCCP (6) and IPPROTO_DCCP (33)
1243 * values directly, Also cover the case where the protocol is not specified,
1244 * i.e. net-pf-PF_INET6-proto-0-type-SOCK_DCCP
1245 */
Jean Delvare7131c6c2007-10-21 16:45:03 -07001246MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_INET6, 33, 6);
1247MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_INET6, 0, 6);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001248MODULE_LICENSE("GPL");
1249MODULE_AUTHOR("Arnaldo Carvalho de Melo <acme@mandriva.com>");
1250MODULE_DESCRIPTION("DCCPv6 - Datagram Congestion Controlled Protocol");