blob: a08af75ddc9ee0c4a8e07632e20b52b0dee62b7b [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
Arnaldo Carvalho de Melo72478872006-03-20 22:00:37 -080036/* Socket used for sending RSTs and ACKs */
37static struct socket *dccp_v6_ctl_socket;
38
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -080039static struct inet_connection_sock_af_ops dccp_ipv6_mapped;
40static struct inet_connection_sock_af_ops dccp_ipv6_af_ops;
41
42static int dccp_v6_get_port(struct sock *sk, unsigned short snum)
43{
44 return inet_csk_get_port(&dccp_hashinfo, sk, snum,
45 inet6_csk_bind_conflict);
46}
47
48static void dccp_v6_hash(struct sock *sk)
49{
50 if (sk->sk_state != DCCP_CLOSED) {
51 if (inet_csk(sk)->icsk_af_ops == &dccp_ipv6_mapped) {
Arnaldo Carvalho de Meloc985ed72006-03-20 21:23:39 -080052 dccp_hash(sk);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -080053 return;
54 }
55 local_bh_disable();
56 __inet6_hash(&dccp_hashinfo, sk);
57 local_bh_enable();
58 }
59}
60
Gerrit Renker6f4e5ff2006-11-10 17:43:06 -020061/* add pseudo-header to DCCP checksum stored in skb->csum */
62static inline u16 dccp_v6_csum_finish(struct sk_buff *skb,
63 struct in6_addr *saddr,
64 struct in6_addr *daddr)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -080065{
Gerrit Renker6f4e5ff2006-11-10 17:43:06 -020066 return csum_ipv6_magic(saddr, daddr, skb->len, IPPROTO_DCCP, skb->csum);
67}
68
69static inline void dccp_v6_send_check(struct sock *sk, int unused_value,
70 struct sk_buff *skb)
71{
72 struct ipv6_pinfo *np = inet6_sk(sk);
73 struct dccp_hdr *dh = dccp_hdr(skb);
74
75 dccp_csum_outgoing(skb);
76 dh->dccph_checksum = dccp_v6_csum_finish(skb, &np->saddr, &np->daddr);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -080077}
78
Gerrit Renker865e9022006-11-13 13:31:50 -020079static inline __u32 dccp_v6_init_sequence(const struct sk_buff *skb)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -080080{
Gerrit Renker865e9022006-11-13 13:31:50 -020081 return secure_tcpv6_sequence_number(skb->nh.ipv6h->daddr.s6_addr32,
82 skb->nh.ipv6h->saddr.s6_addr32,
83 dccp_hdr(skb)->dccph_dport,
84 dccp_hdr(skb)->dccph_sport );
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);
92 struct ipv6_pinfo *np;
93 struct sock *sk;
94 int err;
95 __u64 seq;
96
97 sk = inet6_lookup(&dccp_hashinfo, &hdr->daddr, dh->dccph_dport,
YOSHIFUJI Hideakif2776ff2006-11-21 17:41:56 -080098 &hdr->saddr, dh->dccph_sport, inet6_iif(skb));
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -080099
100 if (sk == NULL) {
101 ICMP6_INC_STATS_BH(__in6_dev_get(skb->dev), ICMP6_MIB_INERRORS);
102 return;
103 }
104
105 if (sk->sk_state == DCCP_TIME_WAIT) {
YOSHIFUJI Hideaki9469c7b2006-10-10 19:41:46 -0700106 inet_twsk_put(inet_twsk(sk));
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800107 return;
108 }
109
110 bh_lock_sock(sk);
111 if (sock_owned_by_user(sk))
112 NET_INC_STATS_BH(LINUX_MIB_LOCKDROPPEDICMPS);
113
114 if (sk->sk_state == DCCP_CLOSED)
115 goto out;
116
117 np = inet6_sk(sk);
118
119 if (type == ICMPV6_PKT_TOOBIG) {
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800120 struct dst_entry *dst = NULL;
121
122 if (sock_owned_by_user(sk))
123 goto out;
124 if ((1 << sk->sk_state) & (DCCPF_LISTEN | DCCPF_CLOSED))
125 goto out;
126
127 /* icmp should have updated the destination cache entry */
128 dst = __sk_dst_check(sk, np->dst_cookie);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800129 if (dst == NULL) {
130 struct inet_sock *inet = inet_sk(sk);
131 struct flowi fl;
132
133 /* BUGGG_FUTURE: Again, it is not clear how
134 to handle rthdr case. Ignore this complexity
135 for now.
136 */
137 memset(&fl, 0, sizeof(fl));
138 fl.proto = IPPROTO_DCCP;
139 ipv6_addr_copy(&fl.fl6_dst, &np->daddr);
140 ipv6_addr_copy(&fl.fl6_src, &np->saddr);
141 fl.oif = sk->sk_bound_dev_if;
142 fl.fl_ip_dport = inet->dport;
143 fl.fl_ip_sport = inet->sport;
Venkat Yekkiralabeb8d132006-08-04 23:12:42 -0700144 security_sk_classify_flow(sk, &fl);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800145
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800146 err = ip6_dst_lookup(sk, &dst, &fl);
147 if (err) {
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800148 sk->sk_err_soft = -err;
149 goto out;
150 }
151
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800152 err = xfrm_lookup(&dst, &fl, sk, 0);
153 if (err < 0) {
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800154 sk->sk_err_soft = -err;
155 goto out;
156 }
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800157 } else
158 dst_hold(dst);
159
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -0800160 if (inet_csk(sk)->icsk_pmtu_cookie > dst_mtu(dst)) {
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800161 dccp_sync_mss(sk, dst_mtu(dst));
162 } /* else let the usual retransmit timer handle it */
163 dst_release(dst);
164 goto out;
165 }
166
167 icmpv6_err_convert(type, code, &err);
168
169 seq = DCCP_SKB_CB(skb)->dccpd_seq;
170 /* Might be for an request_sock */
171 switch (sk->sk_state) {
172 struct request_sock *req, **prev;
173 case DCCP_LISTEN:
174 if (sock_owned_by_user(sk))
175 goto out;
176
177 req = inet6_csk_search_req(sk, &prev, dh->dccph_dport,
178 &hdr->daddr, &hdr->saddr,
179 inet6_iif(skb));
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800180 if (req == NULL)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800181 goto out;
182
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800183 /*
184 * ICMPs are not backlogged, hence we cannot get an established
185 * socket here.
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800186 */
187 BUG_TRAP(req->sk == NULL);
188
189 if (seq != dccp_rsk(req)->dreq_iss) {
190 NET_INC_STATS_BH(LINUX_MIB_OUTOFWINDOWICMPS);
191 goto out;
192 }
193
194 inet_csk_reqsk_queue_drop(sk, req, prev);
195 goto out;
196
197 case DCCP_REQUESTING:
198 case DCCP_RESPOND: /* Cannot happen.
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800199 It can, it SYNs are crossed. --ANK */
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800200 if (!sock_owned_by_user(sk)) {
201 DCCP_INC_STATS_BH(DCCP_MIB_ATTEMPTFAILS);
202 sk->sk_err = err;
203 /*
204 * Wake people up to see the error
205 * (see connect in sock.c)
206 */
207 sk->sk_error_report(sk);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800208 dccp_done(sk);
209 } else
210 sk->sk_err_soft = err;
211 goto out;
212 }
213
214 if (!sock_owned_by_user(sk) && np->recverr) {
215 sk->sk_err = err;
216 sk->sk_error_report(sk);
217 } else
218 sk->sk_err_soft = err;
219
220out:
221 bh_unlock_sock(sk);
222 sock_put(sk);
223}
224
225
226static int dccp_v6_send_response(struct sock *sk, struct request_sock *req,
227 struct dst_entry *dst)
228{
229 struct inet6_request_sock *ireq6 = inet6_rsk(req);
230 struct ipv6_pinfo *np = inet6_sk(sk);
231 struct sk_buff *skb;
232 struct ipv6_txoptions *opt = NULL;
233 struct in6_addr *final_p = NULL, final;
234 struct flowi fl;
235 int err = -1;
236
237 memset(&fl, 0, sizeof(fl));
238 fl.proto = IPPROTO_DCCP;
239 ipv6_addr_copy(&fl.fl6_dst, &ireq6->rmt_addr);
240 ipv6_addr_copy(&fl.fl6_src, &ireq6->loc_addr);
241 fl.fl6_flowlabel = 0;
242 fl.oif = ireq6->iif;
243 fl.fl_ip_dport = inet_rsk(req)->rmt_port;
244 fl.fl_ip_sport = inet_sk(sk)->sport;
Venkat Yekkirala4237c752006-07-24 23:32:50 -0700245 security_req_classify_flow(req, &fl);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800246
247 if (dst == NULL) {
248 opt = np->opt;
249 if (opt == NULL &&
250 np->rxopt.bits.osrcrt == 2 &&
251 ireq6->pktopts) {
252 struct sk_buff *pktopts = ireq6->pktopts;
253 struct inet6_skb_parm *rxopt = IP6CB(pktopts);
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800254
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800255 if (rxopt->srcrt)
256 opt = ipv6_invert_rthdr(sk,
257 (struct ipv6_rt_hdr *)(pktopts->nh.raw +
258 rxopt->srcrt));
259 }
260
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800261 if (opt != NULL && opt->srcrt != NULL) {
262 const struct rt0_hdr *rt0 = (struct rt0_hdr *)opt->srcrt;
263
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800264 ipv6_addr_copy(&final, &fl.fl6_dst);
265 ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
266 final_p = &final;
267 }
268
269 err = ip6_dst_lookup(sk, &dst, &fl);
270 if (err)
271 goto done;
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800272
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800273 if (final_p)
274 ipv6_addr_copy(&fl.fl6_dst, final_p);
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800275
276 err = xfrm_lookup(&dst, &fl, sk, 0);
277 if (err < 0)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800278 goto done;
279 }
280
281 skb = dccp_make_response(sk, dst, req);
282 if (skb != NULL) {
283 struct dccp_hdr *dh = dccp_hdr(skb);
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800284
Gerrit Renker6f4e5ff2006-11-10 17:43:06 -0200285 dh->dccph_checksum = dccp_v6_csum_finish(skb,
286 &ireq6->loc_addr,
287 &ireq6->rmt_addr);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800288 ipv6_addr_copy(&fl.fl6_dst, &ireq6->rmt_addr);
289 err = ip6_xmit(sk, skb, &fl, opt, 0);
290 if (err == NET_XMIT_CN)
291 err = 0;
292 }
293
294done:
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800295 if (opt != NULL && opt != np->opt)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800296 sock_kfree_s(sk, opt, opt->tot_len);
David S. Miller0cbd7822006-01-31 17:53:37 -0800297 dst_release(dst);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800298 return err;
299}
300
301static void dccp_v6_reqsk_destructor(struct request_sock *req)
302{
303 if (inet6_rsk(req)->pktopts != NULL)
304 kfree_skb(inet6_rsk(req)->pktopts);
305}
306
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800307static void dccp_v6_ctl_send_reset(struct sk_buff *rxskb)
308{
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800309 struct dccp_hdr *rxdh = dccp_hdr(rxskb), *dh;
Arnaldo Carvalho de Melo118b2c92006-03-20 22:31:09 -0800310 const u32 dccp_hdr_reset_len = sizeof(struct dccp_hdr) +
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800311 sizeof(struct dccp_hdr_ext) +
312 sizeof(struct dccp_hdr_reset);
313 struct sk_buff *skb;
314 struct flowi fl;
315 u64 seqno;
316
317 if (rxdh->dccph_type == DCCP_PKT_RESET)
318 return;
319
320 if (!ipv6_unicast_destination(rxskb))
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800321 return;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800322
Arnaldo Carvalho de Melo118b2c92006-03-20 22:31:09 -0800323 skb = alloc_skb(dccp_v6_ctl_socket->sk->sk_prot->max_header,
324 GFP_ATOMIC);
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800325 if (skb == NULL)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800326 return;
327
Arnaldo Carvalho de Melo118b2c92006-03-20 22:31:09 -0800328 skb_reserve(skb, dccp_v6_ctl_socket->sk->sk_prot->max_header);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800329
Gerrit Renker9b420782006-11-10 11:22:32 -0200330 dh = dccp_zeroed_hdr(skb, dccp_hdr_reset_len);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800331
332 /* Swap the send and the receive. */
333 dh->dccph_type = DCCP_PKT_RESET;
334 dh->dccph_sport = rxdh->dccph_dport;
335 dh->dccph_dport = rxdh->dccph_sport;
336 dh->dccph_doff = dccp_hdr_reset_len / 4;
337 dh->dccph_x = 1;
338 dccp_hdr_reset(skb)->dccph_reset_code =
339 DCCP_SKB_CB(rxskb)->dccpd_reset_code;
340
Gerrit Renker0e64e942006-10-24 16:17:51 -0700341 /* See "8.3.1. Abnormal Termination" in RFC 4340 */
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800342 seqno = 0;
343 if (DCCP_SKB_CB(rxskb)->dccpd_ack_seq != DCCP_PKT_WITHOUT_ACK_SEQ)
344 dccp_set_seqno(&seqno, DCCP_SKB_CB(rxskb)->dccpd_ack_seq + 1);
345
346 dccp_hdr_set_seq(dh, seqno);
347 dccp_hdr_set_ack(dccp_hdr_ack_bits(skb),
348 DCCP_SKB_CB(rxskb)->dccpd_seq);
349
Gerrit Renker6f4e5ff2006-11-10 17:43:06 -0200350 dccp_csum_outgoing(skb);
351 dh->dccph_checksum = dccp_v6_csum_finish(skb, &rxskb->nh.ipv6h->saddr,
352 &rxskb->nh.ipv6h->daddr);
353
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800354 memset(&fl, 0, sizeof(fl));
355 ipv6_addr_copy(&fl.fl6_dst, &rxskb->nh.ipv6h->saddr);
356 ipv6_addr_copy(&fl.fl6_src, &rxskb->nh.ipv6h->daddr);
Gerrit Renker6f4e5ff2006-11-10 17:43:06 -0200357
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800358 fl.proto = IPPROTO_DCCP;
359 fl.oif = inet6_iif(rxskb);
360 fl.fl_ip_dport = dh->dccph_dport;
361 fl.fl_ip_sport = dh->dccph_sport;
Venkat Yekkiralabeb8d132006-08-04 23:12:42 -0700362 security_skb_classify_flow(rxskb, &fl);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800363
364 /* sk = NULL, but it is safe for now. RST socket required. */
365 if (!ip6_dst_lookup(NULL, &skb->dst, &fl)) {
366 if (xfrm_lookup(&skb->dst, &fl, NULL, 0) >= 0) {
Arnaldo Carvalho de Melo72478872006-03-20 22:00:37 -0800367 ip6_xmit(dccp_v6_ctl_socket->sk, skb, &fl, NULL, 0);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800368 DCCP_INC_STATS_BH(DCCP_MIB_OUTSEGS);
369 DCCP_INC_STATS_BH(DCCP_MIB_OUTRSTS);
370 return;
371 }
372 }
373
374 kfree_skb(skb);
375}
376
Gerrit Renker73c9e022006-11-10 13:01:31 -0200377static struct request_sock_ops dccp6_request_sock_ops = {
378 .family = AF_INET6,
379 .obj_size = sizeof(struct dccp6_request_sock),
380 .rtx_syn_ack = dccp_v6_send_response,
381 .send_ack = dccp_reqsk_send_ack,
382 .destructor = dccp_v6_reqsk_destructor,
383 .send_reset = dccp_v6_ctl_send_reset,
384};
385
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800386static struct sock *dccp_v6_hnd_req(struct sock *sk,struct sk_buff *skb)
387{
388 const struct dccp_hdr *dh = dccp_hdr(skb);
389 const struct ipv6hdr *iph = skb->nh.ipv6h;
390 struct sock *nsk;
391 struct request_sock **prev;
392 /* Find possible connection requests. */
393 struct request_sock *req = inet6_csk_search_req(sk, &prev,
394 dh->dccph_sport,
395 &iph->saddr,
396 &iph->daddr,
397 inet6_iif(skb));
398 if (req != NULL)
399 return dccp_check_req(sk, skb, req, prev);
400
401 nsk = __inet6_lookup_established(&dccp_hashinfo,
402 &iph->saddr, dh->dccph_sport,
403 &iph->daddr, ntohs(dh->dccph_dport),
404 inet6_iif(skb));
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800405 if (nsk != NULL) {
406 if (nsk->sk_state != DCCP_TIME_WAIT) {
407 bh_lock_sock(nsk);
408 return nsk;
409 }
YOSHIFUJI Hideaki9469c7b2006-10-10 19:41:46 -0700410 inet_twsk_put(inet_twsk(nsk));
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800411 return NULL;
412 }
413
414 return sk;
415}
416
417static int dccp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
418{
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800419 struct request_sock *req;
420 struct dccp_request_sock *dreq;
421 struct inet6_request_sock *ireq6;
422 struct ipv6_pinfo *np = inet6_sk(sk);
Andrea Bittau60fe62e2006-03-20 19:23:32 -0800423 const __be32 service = dccp_hdr_request(skb)->dccph_req_service;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800424 struct dccp_skb_cb *dcb = DCCP_SKB_CB(skb);
425 __u8 reset_code = DCCP_RESET_CODE_TOO_BUSY;
426
427 if (skb->protocol == htons(ETH_P_IP))
428 return dccp_v4_conn_request(sk, skb);
429
430 if (!ipv6_unicast_destination(skb))
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800431 goto drop;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800432
433 if (dccp_bad_service_code(sk, service)) {
434 reset_code = DCCP_RESET_CODE_BAD_SERVICE_CODE;
435 goto drop;
436 }
437 /*
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800438 * There are no SYN attacks on IPv6, yet...
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800439 */
440 if (inet_csk_reqsk_queue_is_full(sk))
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800441 goto drop;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800442
443 if (sk_acceptq_is_full(sk) && inet_csk_reqsk_queue_young(sk) > 1)
444 goto drop;
445
Gerrit Renker82709532006-10-11 16:26:54 +0100446 req = inet6_reqsk_alloc(&dccp6_request_sock_ops);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800447 if (req == NULL)
448 goto drop;
449
Gerrit Renkercf557922006-11-10 16:08:37 -0200450 if (dccp_parse_options(sk, skb))
451 goto drop_and_free;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800452
Gerrit Renkercf557922006-11-10 16:08:37 -0200453 dccp_reqsk_init(req, skb);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800454
Venkat Yekkirala4237c752006-07-24 23:32:50 -0700455 if (security_inet_conn_request(sk, skb, req))
456 goto drop_and_free;
457
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800458 ireq6 = inet6_rsk(req);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800459 ipv6_addr_copy(&ireq6->rmt_addr, &skb->nh.ipv6h->saddr);
460 ipv6_addr_copy(&ireq6->loc_addr, &skb->nh.ipv6h->daddr);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800461 ireq6->pktopts = NULL;
462
463 if (ipv6_opt_accepted(sk, skb) ||
464 np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo ||
465 np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim) {
466 atomic_inc(&skb->users);
467 ireq6->pktopts = skb;
468 }
469 ireq6->iif = sk->sk_bound_dev_if;
470
471 /* So that link locals have meaning */
472 if (!sk->sk_bound_dev_if &&
473 ipv6_addr_type(&ireq6->rmt_addr) & IPV6_ADDR_LINKLOCAL)
474 ireq6->iif = inet6_iif(skb);
475
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800476 /*
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800477 * Step 3: Process LISTEN state
478 *
Gerrit Renkerd83ca5a2006-11-10 16:29:14 -0200479 * Set S.ISR, S.GSR, S.SWL, S.SWH from packet or Init Cookie
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800480 *
Gerrit Renkerd83ca5a2006-11-10 16:29:14 -0200481 * In fact we defer setting S.GSR, S.SWL, S.SWH to
482 * dccp_create_openreq_child.
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800483 */
484 dreq = dccp_rsk(req);
485 dreq->dreq_isr = dcb->dccpd_seq;
Gerrit Renker865e9022006-11-13 13:31:50 -0200486 dreq->dreq_iss = dccp_v6_init_sequence(skb);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800487 dreq->dreq_service = service;
488
489 if (dccp_v6_send_response(sk, req, NULL))
490 goto drop_and_free;
491
492 inet6_csk_reqsk_queue_hash_add(sk, req, DCCP_TIMEOUT_INIT);
493 return 0;
494
495drop_and_free:
496 reqsk_free(req);
497drop:
498 DCCP_INC_STATS_BH(DCCP_MIB_ATTEMPTFAILS);
499 dcb->dccpd_reset_code = reset_code;
500 return -1;
501}
502
503static struct sock *dccp_v6_request_recv_sock(struct sock *sk,
504 struct sk_buff *skb,
505 struct request_sock *req,
506 struct dst_entry *dst)
507{
508 struct inet6_request_sock *ireq6 = inet6_rsk(req);
509 struct ipv6_pinfo *newnp, *np = inet6_sk(sk);
510 struct inet_sock *newinet;
511 struct dccp_sock *newdp;
512 struct dccp6_sock *newdp6;
513 struct sock *newsk;
514 struct ipv6_txoptions *opt;
515
516 if (skb->protocol == htons(ETH_P_IP)) {
517 /*
518 * v6 mapped
519 */
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800520 newsk = dccp_v4_request_recv_sock(sk, skb, req, dst);
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800521 if (newsk == NULL)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800522 return NULL;
523
524 newdp6 = (struct dccp6_sock *)newsk;
525 newdp = dccp_sk(newsk);
526 newinet = inet_sk(newsk);
527 newinet->pinet6 = &newdp6->inet6;
528 newnp = inet6_sk(newsk);
529
530 memcpy(newnp, np, sizeof(struct ipv6_pinfo));
531
532 ipv6_addr_set(&newnp->daddr, 0, 0, htonl(0x0000FFFF),
533 newinet->daddr);
534
535 ipv6_addr_set(&newnp->saddr, 0, 0, htonl(0x0000FFFF),
536 newinet->saddr);
537
538 ipv6_addr_copy(&newnp->rcv_saddr, &newnp->saddr);
539
540 inet_csk(newsk)->icsk_af_ops = &dccp_ipv6_mapped;
541 newsk->sk_backlog_rcv = dccp_v4_do_rcv;
542 newnp->pktoptions = NULL;
543 newnp->opt = NULL;
544 newnp->mcast_oif = inet6_iif(skb);
545 newnp->mcast_hops = skb->nh.ipv6h->hop_limit;
546
547 /*
548 * No need to charge this sock to the relevant IPv6 refcnt debug socks count
549 * here, dccp_create_openreq_child now does this for us, see the comment in
550 * that function for the gory details. -acme
551 */
552
553 /* It is tricky place. Until this moment IPv4 tcp
554 worked with IPv6 icsk.icsk_af_ops.
555 Sync it now.
556 */
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -0800557 dccp_sync_mss(newsk, inet_csk(newsk)->icsk_pmtu_cookie);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800558
559 return newsk;
560 }
561
562 opt = np->opt;
563
564 if (sk_acceptq_is_full(sk))
565 goto out_overflow;
566
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800567 if (np->rxopt.bits.osrcrt == 2 && opt == NULL && ireq6->pktopts) {
568 const struct inet6_skb_parm *rxopt = IP6CB(ireq6->pktopts);
569
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800570 if (rxopt->srcrt)
571 opt = ipv6_invert_rthdr(sk,
572 (struct ipv6_rt_hdr *)(ireq6->pktopts->nh.raw +
573 rxopt->srcrt));
574 }
575
576 if (dst == NULL) {
577 struct in6_addr *final_p = NULL, final;
578 struct flowi fl;
579
580 memset(&fl, 0, sizeof(fl));
581 fl.proto = IPPROTO_DCCP;
582 ipv6_addr_copy(&fl.fl6_dst, &ireq6->rmt_addr);
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800583 if (opt != NULL && opt->srcrt != NULL) {
584 const struct rt0_hdr *rt0 = (struct rt0_hdr *)opt->srcrt;
585
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800586 ipv6_addr_copy(&final, &fl.fl6_dst);
587 ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
588 final_p = &final;
589 }
590 ipv6_addr_copy(&fl.fl6_src, &ireq6->loc_addr);
591 fl.oif = sk->sk_bound_dev_if;
592 fl.fl_ip_dport = inet_rsk(req)->rmt_port;
593 fl.fl_ip_sport = inet_sk(sk)->sport;
Venkat Yekkiralabeb8d132006-08-04 23:12:42 -0700594 security_sk_classify_flow(sk, &fl);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800595
596 if (ip6_dst_lookup(sk, &dst, &fl))
597 goto out;
598
599 if (final_p)
600 ipv6_addr_copy(&fl.fl6_dst, final_p);
601
602 if ((xfrm_lookup(&dst, &fl, sk, 0)) < 0)
603 goto out;
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800604 }
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800605
606 newsk = dccp_create_openreq_child(sk, req, skb);
607 if (newsk == NULL)
608 goto out;
609
610 /*
611 * No need to charge this sock to the relevant IPv6 refcnt debug socks
612 * count here, dccp_create_openreq_child now does this for us, see the
613 * comment in that function for the gory details. -acme
614 */
615
YOSHIFUJI Hideaki8e1ef0a2006-08-29 17:15:09 -0700616 __ip6_dst_store(newsk, dst, NULL, NULL);
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800617 newsk->sk_route_caps = dst->dev->features & ~(NETIF_F_IP_CSUM |
618 NETIF_F_TSO);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800619 newdp6 = (struct dccp6_sock *)newsk;
620 newinet = inet_sk(newsk);
621 newinet->pinet6 = &newdp6->inet6;
622 newdp = dccp_sk(newsk);
623 newnp = inet6_sk(newsk);
624
625 memcpy(newnp, np, sizeof(struct ipv6_pinfo));
626
627 ipv6_addr_copy(&newnp->daddr, &ireq6->rmt_addr);
628 ipv6_addr_copy(&newnp->saddr, &ireq6->loc_addr);
629 ipv6_addr_copy(&newnp->rcv_saddr, &ireq6->loc_addr);
630 newsk->sk_bound_dev_if = ireq6->iif;
631
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800632 /* Now IPv6 options...
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800633
634 First: no IPv4 options.
635 */
636 newinet->opt = NULL;
637
638 /* Clone RX bits */
639 newnp->rxopt.all = np->rxopt.all;
640
641 /* Clone pktoptions received with SYN */
642 newnp->pktoptions = NULL;
643 if (ireq6->pktopts != NULL) {
644 newnp->pktoptions = skb_clone(ireq6->pktopts, GFP_ATOMIC);
645 kfree_skb(ireq6->pktopts);
646 ireq6->pktopts = NULL;
647 if (newnp->pktoptions)
648 skb_set_owner_r(newnp->pktoptions, newsk);
649 }
650 newnp->opt = NULL;
651 newnp->mcast_oif = inet6_iif(skb);
652 newnp->mcast_hops = skb->nh.ipv6h->hop_limit;
653
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800654 /*
655 * Clone native IPv6 options from listening socket (if any)
656 *
657 * Yes, keeping reference count would be much more clever, but we make
658 * one more one thing there: reattach optmem to newsk.
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800659 */
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800660 if (opt != NULL) {
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800661 newnp->opt = ipv6_dup_options(newsk, opt);
662 if (opt != np->opt)
663 sock_kfree_s(sk, opt, opt->tot_len);
664 }
665
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -0800666 inet_csk(newsk)->icsk_ext_hdr_len = 0;
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800667 if (newnp->opt != NULL)
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -0800668 inet_csk(newsk)->icsk_ext_hdr_len = (newnp->opt->opt_nflen +
669 newnp->opt->opt_flen);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800670
671 dccp_sync_mss(newsk, dst_mtu(dst));
672
673 newinet->daddr = newinet->saddr = newinet->rcv_saddr = LOOPBACK4_IPV6;
674
675 __inet6_hash(&dccp_hashinfo, newsk);
676 inet_inherit_port(&dccp_hashinfo, sk, newsk);
677
678 return newsk;
679
680out_overflow:
681 NET_INC_STATS_BH(LINUX_MIB_LISTENOVERFLOWS);
682out:
683 NET_INC_STATS_BH(LINUX_MIB_LISTENDROPS);
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800684 if (opt != NULL && opt != np->opt)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800685 sock_kfree_s(sk, opt, opt->tot_len);
686 dst_release(dst);
687 return NULL;
688}
689
690/* The socket must have it's spinlock held when we get
691 * here.
692 *
693 * We have a potential double-lock case here, so even when
694 * doing backlog processing we use the BH locking scheme.
695 * This is because we cannot sleep with the original spinlock
696 * held.
697 */
698static int dccp_v6_do_rcv(struct sock *sk, struct sk_buff *skb)
699{
700 struct ipv6_pinfo *np = inet6_sk(sk);
701 struct sk_buff *opt_skb = NULL;
702
703 /* Imagine: socket is IPv6. IPv4 packet arrives,
704 goes to IPv4 receive handler and backlogged.
705 From backlog it always goes here. Kerboom...
706 Fortunately, dccp_rcv_established and rcv_established
707 handle them correctly, but it is not case with
708 dccp_v6_hnd_req and dccp_v6_ctl_send_reset(). --ANK
709 */
710
711 if (skb->protocol == htons(ETH_P_IP))
712 return dccp_v4_do_rcv(sk, skb);
713
Dmitry Mishinfda9ef52006-08-31 15:28:39 -0700714 if (sk_filter(sk, skb))
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800715 goto discard;
716
717 /*
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800718 * socket locking is here for SMP purposes as backlog rcv is currently
719 * called with bh processing disabled.
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800720 */
721
722 /* Do Stevens' IPV6_PKTOPTIONS.
723
724 Yes, guys, it is the only place in our code, where we
725 may make it not affecting IPv4.
726 The rest of code is protocol independent,
727 and I do not like idea to uglify IPv4.
728
729 Actually, all the idea behind IPV6_PKTOPTIONS
730 looks not very well thought. For now we latch
731 options, received in the last packet, enqueued
732 by tcp. Feel free to propose better solution.
733 --ANK (980728)
734 */
735 if (np->rxopt.all)
Gerrit Renker89e7e572006-11-10 11:13:33 -0200736 /*
737 * FIXME: Add handling of IPV6_PKTOPTIONS skb. See the comments below
738 * (wrt ipv6_pktopions) and net/ipv6/tcp_ipv6.c for an example.
739 */
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800740 opt_skb = skb_clone(skb, GFP_ATOMIC);
741
742 if (sk->sk_state == DCCP_OPEN) { /* Fast path */
743 if (dccp_rcv_established(sk, skb, dccp_hdr(skb), skb->len))
744 goto reset;
David S. Millerfd169f12006-10-20 19:44:17 -0700745 if (opt_skb) {
Gerrit Renker89e7e572006-11-10 11:13:33 -0200746 /* XXX This is where we would goto ipv6_pktoptions. */
David S. Millerfd169f12006-10-20 19:44:17 -0700747 __kfree_skb(opt_skb);
748 }
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800749 return 0;
750 }
751
Gerrit Renkerd83ca5a2006-11-10 16:29:14 -0200752 /*
753 * Step 3: Process LISTEN state
754 * If S.state == LISTEN,
755 * If P.type == Request or P contains a valid Init Cookie option,
756 * (* Must scan the packet's options to check for Init
757 * Cookies. Only Init Cookies are processed here,
758 * however; other options are processed in Step 8. This
759 * scan need only be performed if the endpoint uses Init
760 * Cookies *)
761 * (* Generate a new socket and switch to that socket *)
762 * Set S := new socket for this port pair
763 * S.state = RESPOND
764 * Choose S.ISS (initial seqno) or set from Init Cookies
765 * Initialize S.GAR := S.ISS
766 * Set S.ISR, S.GSR, S.SWL, S.SWH from packet or Init Cookies
767 * Continue with S.state == RESPOND
768 * (* A Response packet will be generated in Step 11 *)
769 * Otherwise,
770 * Generate Reset(No Connection) unless P.type == Reset
771 * Drop packet and return
772 *
773 * NOTE: the check for the packet types is done in
774 * dccp_rcv_state_process
775 */
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800776 if (sk->sk_state == DCCP_LISTEN) {
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800777 struct sock *nsk = dccp_v6_hnd_req(sk, skb);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800778
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800779 if (nsk == NULL)
780 goto discard;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800781 /*
782 * Queue it on the new socket if the new socket is active,
783 * otherwise we just shortcircuit this and continue with
784 * the new socket..
785 */
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800786 if (nsk != sk) {
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800787 if (dccp_child_process(sk, nsk, skb))
788 goto reset;
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800789 if (opt_skb != NULL)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800790 __kfree_skb(opt_skb);
791 return 0;
792 }
793 }
794
795 if (dccp_rcv_state_process(sk, skb, dccp_hdr(skb), skb->len))
796 goto reset;
David S. Millerfd169f12006-10-20 19:44:17 -0700797 if (opt_skb) {
Gerrit Renker89e7e572006-11-10 11:13:33 -0200798 /* XXX This is where we would goto ipv6_pktoptions. */
David S. Millerfd169f12006-10-20 19:44:17 -0700799 __kfree_skb(opt_skb);
800 }
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800801 return 0;
802
803reset:
804 dccp_v6_ctl_send_reset(skb);
805discard:
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800806 if (opt_skb != NULL)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800807 __kfree_skb(opt_skb);
808 kfree_skb(skb);
809 return 0;
810}
811
Patrick McHardy951dbc82006-01-06 23:02:34 -0800812static int dccp_v6_rcv(struct sk_buff **pskb)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800813{
814 const struct dccp_hdr *dh;
815 struct sk_buff *skb = *pskb;
816 struct sock *sk;
Gerrit Renker6f4e5ff2006-11-10 17:43:06 -0200817 int min_cov;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800818
Gerrit Renker6f4e5ff2006-11-10 17:43:06 -0200819 /* Step 1: Check header basics */
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800820
821 if (dccp_invalid_packet(skb))
822 goto discard_it;
823
Gerrit Renker6f4e5ff2006-11-10 17:43:06 -0200824 /* Step 1: If header checksum is incorrect, drop packet and return. */
825 if (dccp_v6_csum_finish(skb, &skb->nh.ipv6h->saddr,
826 &skb->nh.ipv6h->daddr)) {
827 LIMIT_NETDEBUG(KERN_WARNING
828 "%s: dropped packet with invalid checksum\n",
829 __FUNCTION__);
830 goto discard_it;
831 }
832
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800833 dh = dccp_hdr(skb);
834
835 DCCP_SKB_CB(skb)->dccpd_seq = dccp_hdr_seq(skb);
836 DCCP_SKB_CB(skb)->dccpd_type = dh->dccph_type;
837
838 if (dccp_packet_without_ack(skb))
839 DCCP_SKB_CB(skb)->dccpd_ack_seq = DCCP_PKT_WITHOUT_ACK_SEQ;
840 else
841 DCCP_SKB_CB(skb)->dccpd_ack_seq = dccp_hdr_ack_seq(skb);
842
843 /* Step 2:
844 * Look up flow ID in table and get corresponding socket */
845 sk = __inet6_lookup(&dccp_hashinfo, &skb->nh.ipv6h->saddr,
846 dh->dccph_sport,
847 &skb->nh.ipv6h->daddr, ntohs(dh->dccph_dport),
848 inet6_iif(skb));
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800849 /*
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800850 * Step 2:
851 * If no socket ...
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800852 */
Gerrit Renkerd23c7102006-11-10 11:46:34 -0200853 if (sk == NULL) {
854 dccp_pr_debug("failed to look up flow ID in table and "
855 "get corresponding socket\n");
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800856 goto no_dccp_socket;
Gerrit Renkerd23c7102006-11-10 11:46:34 -0200857 }
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800858
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800859 /*
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800860 * Step 2:
861 * ... or S.state == TIMEWAIT,
862 * Generate Reset(No Connection) unless P.type == Reset
863 * Drop packet and return
864 */
Gerrit Renkerd23c7102006-11-10 11:46:34 -0200865 if (sk->sk_state == DCCP_TIME_WAIT) {
866 dccp_pr_debug("sk->sk_state == DCCP_TIME_WAIT: do_time_wait\n");
867 inet_twsk_put(inet_twsk(sk));
868 goto no_dccp_socket;
869 }
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800870
Gerrit Renker6f4e5ff2006-11-10 17:43:06 -0200871 /*
872 * RFC 4340, sec. 9.2.1: Minimum Checksum Coverage
873 * o if MinCsCov = 0, only packets with CsCov = 0 are accepted
874 * o if MinCsCov > 0, also accept packets with CsCov >= MinCsCov
875 */
876 min_cov = dccp_sk(sk)->dccps_pcrlen;
877 if (dh->dccph_cscov && (min_cov == 0 || dh->dccph_cscov < min_cov)) {
878 dccp_pr_debug("Packet CsCov %d does not satisfy MinCsCov %d\n",
879 dh->dccph_cscov, min_cov);
880 /* FIXME: send Data Dropped option (see also dccp_v4_rcv) */
881 goto discard_and_relse;
882 }
883
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800884 if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb))
885 goto discard_and_relse;
886
Arnaldo Carvalho de Melo25995ff2005-12-27 02:42:22 -0200887 return sk_receive_skb(sk, skb) ? -1 : 0;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800888
889no_dccp_socket:
890 if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb))
891 goto discard_it;
892 /*
893 * Step 2:
Gerrit Renkerd83ca5a2006-11-10 16:29:14 -0200894 * If no socket ...
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800895 * Generate Reset(No Connection) unless P.type == Reset
896 * Drop packet and return
897 */
898 if (dh->dccph_type != DCCP_PKT_RESET) {
899 DCCP_SKB_CB(skb)->dccpd_reset_code =
900 DCCP_RESET_CODE_NO_CONNECTION;
901 dccp_v6_ctl_send_reset(skb);
902 }
Gerrit Renkerd23c7102006-11-10 11:46:34 -0200903
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800904discard_it:
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800905 kfree_skb(skb);
906 return 0;
907
908discard_and_relse:
909 sock_put(sk);
910 goto discard_it;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800911}
912
Gerrit Renker73c9e022006-11-10 13:01:31 -0200913static int dccp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
914 int addr_len)
915{
916 struct sockaddr_in6 *usin = (struct sockaddr_in6 *)uaddr;
917 struct inet_connection_sock *icsk = inet_csk(sk);
918 struct inet_sock *inet = inet_sk(sk);
919 struct ipv6_pinfo *np = inet6_sk(sk);
920 struct dccp_sock *dp = dccp_sk(sk);
921 struct in6_addr *saddr = NULL, *final_p = NULL, final;
922 struct flowi fl;
923 struct dst_entry *dst;
924 int addr_type;
925 int err;
926
927 dp->dccps_role = DCCP_ROLE_CLIENT;
928
929 if (addr_len < SIN6_LEN_RFC2133)
930 return -EINVAL;
931
932 if (usin->sin6_family != AF_INET6)
933 return -EAFNOSUPPORT;
934
935 memset(&fl, 0, sizeof(fl));
936
937 if (np->sndflow) {
938 fl.fl6_flowlabel = usin->sin6_flowinfo & IPV6_FLOWINFO_MASK;
939 IP6_ECN_flow_init(fl.fl6_flowlabel);
940 if (fl.fl6_flowlabel & IPV6_FLOWLABEL_MASK) {
941 struct ip6_flowlabel *flowlabel;
942 flowlabel = fl6_sock_lookup(sk, fl.fl6_flowlabel);
943 if (flowlabel == NULL)
944 return -EINVAL;
945 ipv6_addr_copy(&usin->sin6_addr, &flowlabel->dst);
946 fl6_sock_release(flowlabel);
947 }
948 }
949 /*
950 * connect() to INADDR_ANY means loopback (BSD'ism).
951 */
952 if (ipv6_addr_any(&usin->sin6_addr))
953 usin->sin6_addr.s6_addr[15] = 1;
954
955 addr_type = ipv6_addr_type(&usin->sin6_addr);
956
957 if (addr_type & IPV6_ADDR_MULTICAST)
958 return -ENETUNREACH;
959
960 if (addr_type & IPV6_ADDR_LINKLOCAL) {
961 if (addr_len >= sizeof(struct sockaddr_in6) &&
962 usin->sin6_scope_id) {
963 /* If interface is set while binding, indices
964 * must coincide.
965 */
966 if (sk->sk_bound_dev_if &&
967 sk->sk_bound_dev_if != usin->sin6_scope_id)
968 return -EINVAL;
969
970 sk->sk_bound_dev_if = usin->sin6_scope_id;
971 }
972
973 /* Connect to link-local address requires an interface */
974 if (!sk->sk_bound_dev_if)
975 return -EINVAL;
976 }
977
978 ipv6_addr_copy(&np->daddr, &usin->sin6_addr);
979 np->flow_label = fl.fl6_flowlabel;
980
981 /*
982 * DCCP over IPv4
983 */
984 if (addr_type == IPV6_ADDR_MAPPED) {
985 u32 exthdrlen = icsk->icsk_ext_hdr_len;
986 struct sockaddr_in sin;
987
988 SOCK_DEBUG(sk, "connect: ipv4 mapped\n");
989
990 if (__ipv6_only_sock(sk))
991 return -ENETUNREACH;
992
993 sin.sin_family = AF_INET;
994 sin.sin_port = usin->sin6_port;
995 sin.sin_addr.s_addr = usin->sin6_addr.s6_addr32[3];
996
997 icsk->icsk_af_ops = &dccp_ipv6_mapped;
998 sk->sk_backlog_rcv = dccp_v4_do_rcv;
999
1000 err = dccp_v4_connect(sk, (struct sockaddr *)&sin, sizeof(sin));
1001 if (err) {
1002 icsk->icsk_ext_hdr_len = exthdrlen;
1003 icsk->icsk_af_ops = &dccp_ipv6_af_ops;
1004 sk->sk_backlog_rcv = dccp_v6_do_rcv;
1005 goto failure;
1006 } else {
1007 ipv6_addr_set(&np->saddr, 0, 0, htonl(0x0000FFFF),
1008 inet->saddr);
1009 ipv6_addr_set(&np->rcv_saddr, 0, 0, htonl(0x0000FFFF),
1010 inet->rcv_saddr);
1011 }
1012
1013 return err;
1014 }
1015
1016 if (!ipv6_addr_any(&np->rcv_saddr))
1017 saddr = &np->rcv_saddr;
1018
1019 fl.proto = IPPROTO_DCCP;
1020 ipv6_addr_copy(&fl.fl6_dst, &np->daddr);
1021 ipv6_addr_copy(&fl.fl6_src, saddr ? saddr : &np->saddr);
1022 fl.oif = sk->sk_bound_dev_if;
1023 fl.fl_ip_dport = usin->sin6_port;
1024 fl.fl_ip_sport = inet->sport;
1025 security_sk_classify_flow(sk, &fl);
1026
1027 if (np->opt != NULL && np->opt->srcrt != NULL) {
1028 const struct rt0_hdr *rt0 = (struct rt0_hdr *)np->opt->srcrt;
1029
1030 ipv6_addr_copy(&final, &fl.fl6_dst);
1031 ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
1032 final_p = &final;
1033 }
1034
1035 err = ip6_dst_lookup(sk, &dst, &fl);
1036 if (err)
1037 goto failure;
1038
1039 if (final_p)
1040 ipv6_addr_copy(&fl.fl6_dst, final_p);
1041
1042 err = xfrm_lookup(&dst, &fl, sk, 0);
1043 if (err < 0)
1044 goto failure;
1045
1046 if (saddr == NULL) {
1047 saddr = &fl.fl6_src;
1048 ipv6_addr_copy(&np->rcv_saddr, saddr);
1049 }
1050
1051 /* set the source address */
1052 ipv6_addr_copy(&np->saddr, saddr);
1053 inet->rcv_saddr = LOOPBACK4_IPV6;
1054
1055 __ip6_dst_store(sk, dst, NULL, NULL);
1056
1057 icsk->icsk_ext_hdr_len = 0;
1058 if (np->opt != NULL)
1059 icsk->icsk_ext_hdr_len = (np->opt->opt_flen +
1060 np->opt->opt_nflen);
1061
1062 inet->dport = usin->sin6_port;
1063
1064 dccp_set_state(sk, DCCP_REQUESTING);
1065 err = inet6_hash_connect(&dccp_death_row, sk);
1066 if (err)
1067 goto late_failure;
1068 /* FIXME */
1069#if 0
1070 dp->dccps_gar = secure_dccp_v6_sequence_number(np->saddr.s6_addr32,
1071 np->daddr.s6_addr32,
1072 inet->sport,
1073 inet->dport);
1074#endif
1075 err = dccp_connect(sk);
1076 if (err)
1077 goto late_failure;
1078
1079 return 0;
1080
1081late_failure:
1082 dccp_set_state(sk, DCCP_CLOSED);
1083 __sk_dst_reset(sk);
1084failure:
1085 inet->dport = 0;
1086 sk->sk_route_caps = 0;
1087 return err;
1088}
1089
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001090static struct inet_connection_sock_af_ops dccp_ipv6_af_ops = {
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001091 .queue_xmit = inet6_csk_xmit,
1092 .send_check = dccp_v6_send_check,
1093 .rebuild_header = inet6_sk_rebuild_header,
1094 .conn_request = dccp_v6_conn_request,
1095 .syn_recv_sock = dccp_v6_request_recv_sock,
1096 .net_header_len = sizeof(struct ipv6hdr),
1097 .setsockopt = ipv6_setsockopt,
1098 .getsockopt = ipv6_getsockopt,
1099 .addr2sockaddr = inet6_csk_addr2sockaddr,
1100 .sockaddr_len = sizeof(struct sockaddr_in6),
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001101#ifdef CONFIG_COMPAT
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001102 .compat_setsockopt = compat_ipv6_setsockopt,
1103 .compat_getsockopt = compat_ipv6_getsockopt,
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001104#endif
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001105};
1106
1107/*
1108 * DCCP over IPv4 via INET6 API
1109 */
1110static struct inet_connection_sock_af_ops dccp_ipv6_mapped = {
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001111 .queue_xmit = ip_queue_xmit,
1112 .send_check = dccp_v4_send_check,
1113 .rebuild_header = inet_sk_rebuild_header,
1114 .conn_request = dccp_v6_conn_request,
1115 .syn_recv_sock = dccp_v6_request_recv_sock,
1116 .net_header_len = sizeof(struct iphdr),
1117 .setsockopt = ipv6_setsockopt,
1118 .getsockopt = ipv6_getsockopt,
1119 .addr2sockaddr = inet6_csk_addr2sockaddr,
1120 .sockaddr_len = sizeof(struct sockaddr_in6),
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001121#ifdef CONFIG_COMPAT
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001122 .compat_setsockopt = compat_ipv6_setsockopt,
1123 .compat_getsockopt = compat_ipv6_getsockopt,
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001124#endif
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001125};
1126
1127/* NOTE: A lot of things set to zero explicitly by call to
1128 * sk_alloc() so need not be done here.
1129 */
1130static int dccp_v6_init_sock(struct sock *sk)
1131{
Arnaldo Carvalho de Melo72478872006-03-20 22:00:37 -08001132 static __u8 dccp_v6_ctl_sock_initialized;
1133 int err = dccp_init_sock(sk, dccp_v6_ctl_sock_initialized);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001134
Arnaldo Carvalho de Melo72478872006-03-20 22:00:37 -08001135 if (err == 0) {
1136 if (unlikely(!dccp_v6_ctl_sock_initialized))
1137 dccp_v6_ctl_sock_initialized = 1;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001138 inet_csk(sk)->icsk_af_ops = &dccp_ipv6_af_ops;
Arnaldo Carvalho de Melo72478872006-03-20 22:00:37 -08001139 }
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001140
1141 return err;
1142}
1143
1144static int dccp_v6_destroy_sock(struct sock *sk)
1145{
Arnaldo Carvalho de Melo3e0fadc2006-03-20 21:23:15 -08001146 dccp_destroy_sock(sk);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001147 return inet6_destroy_sock(sk);
1148}
1149
Gerrit Renker73c9e022006-11-10 13:01:31 -02001150static struct timewait_sock_ops dccp6_timewait_sock_ops = {
1151 .twsk_obj_size = sizeof(struct dccp6_timewait_sock),
1152};
1153
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001154static struct proto dccp_v6_prot = {
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001155 .name = "DCCPv6",
1156 .owner = THIS_MODULE,
1157 .close = dccp_close,
1158 .connect = dccp_v6_connect,
1159 .disconnect = dccp_disconnect,
1160 .ioctl = dccp_ioctl,
1161 .init = dccp_v6_init_sock,
1162 .setsockopt = dccp_setsockopt,
1163 .getsockopt = dccp_getsockopt,
1164 .sendmsg = dccp_sendmsg,
1165 .recvmsg = dccp_recvmsg,
1166 .backlog_rcv = dccp_v6_do_rcv,
1167 .hash = dccp_v6_hash,
1168 .unhash = dccp_unhash,
1169 .accept = inet_csk_accept,
1170 .get_port = dccp_v6_get_port,
1171 .shutdown = dccp_shutdown,
1172 .destroy = dccp_v6_destroy_sock,
1173 .orphan_count = &dccp_orphan_count,
1174 .max_header = MAX_DCCP_HEADER,
1175 .obj_size = sizeof(struct dccp6_sock),
1176 .rsk_prot = &dccp6_request_sock_ops,
1177 .twsk_prot = &dccp6_timewait_sock_ops,
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001178#ifdef CONFIG_COMPAT
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001179 .compat_setsockopt = compat_dccp_setsockopt,
1180 .compat_getsockopt = compat_dccp_getsockopt,
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001181#endif
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001182};
1183
1184static struct inet6_protocol dccp_v6_protocol = {
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -08001185 .handler = dccp_v6_rcv,
1186 .err_handler = dccp_v6_err,
1187 .flags = INET6_PROTO_NOPOLICY | INET6_PROTO_FINAL,
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001188};
1189
1190static struct proto_ops inet6_dccp_ops = {
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001191 .family = PF_INET6,
1192 .owner = THIS_MODULE,
1193 .release = inet6_release,
1194 .bind = inet6_bind,
1195 .connect = inet_stream_connect,
1196 .socketpair = sock_no_socketpair,
1197 .accept = inet_accept,
1198 .getname = inet6_getname,
1199 .poll = dccp_poll,
1200 .ioctl = inet6_ioctl,
1201 .listen = inet_dccp_listen,
1202 .shutdown = inet_shutdown,
1203 .setsockopt = sock_common_setsockopt,
1204 .getsockopt = sock_common_getsockopt,
1205 .sendmsg = inet_sendmsg,
1206 .recvmsg = sock_common_recvmsg,
1207 .mmap = sock_no_mmap,
1208 .sendpage = sock_no_sendpage,
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001209#ifdef CONFIG_COMPAT
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001210 .compat_setsockopt = compat_sock_common_setsockopt,
1211 .compat_getsockopt = compat_sock_common_getsockopt,
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001212#endif
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001213};
1214
1215static struct inet_protosw dccp_v6_protosw = {
1216 .type = SOCK_DCCP,
1217 .protocol = IPPROTO_DCCP,
1218 .prot = &dccp_v6_prot,
1219 .ops = &inet6_dccp_ops,
1220 .capability = -1,
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -08001221 .flags = INET_PROTOSW_ICSK,
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001222};
1223
1224static int __init dccp_v6_init(void)
1225{
1226 int err = proto_register(&dccp_v6_prot, 1);
1227
1228 if (err != 0)
1229 goto out;
1230
1231 err = inet6_add_protocol(&dccp_v6_protocol, IPPROTO_DCCP);
1232 if (err != 0)
1233 goto out_unregister_proto;
1234
1235 inet6_register_protosw(&dccp_v6_protosw);
Arnaldo Carvalho de Melo72478872006-03-20 22:00:37 -08001236
Arnaldo Carvalho de Meloc4d93902006-03-20 22:01:03 -08001237 err = inet_csk_ctl_sock_create(&dccp_v6_ctl_socket, PF_INET6,
1238 SOCK_DCCP, IPPROTO_DCCP);
1239 if (err != 0)
Arnaldo Carvalho de Melo72478872006-03-20 22:00:37 -08001240 goto out_unregister_protosw;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001241out:
1242 return err;
Arnaldo Carvalho de Melo72478872006-03-20 22:00:37 -08001243out_unregister_protosw:
1244 inet6_del_protocol(&dccp_v6_protocol, IPPROTO_DCCP);
1245 inet6_unregister_protosw(&dccp_v6_protosw);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001246out_unregister_proto:
1247 proto_unregister(&dccp_v6_prot);
1248 goto out;
1249}
1250
1251static void __exit dccp_v6_exit(void)
1252{
1253 inet6_del_protocol(&dccp_v6_protocol, IPPROTO_DCCP);
1254 inet6_unregister_protosw(&dccp_v6_protosw);
1255 proto_unregister(&dccp_v6_prot);
1256}
1257
1258module_init(dccp_v6_init);
1259module_exit(dccp_v6_exit);
1260
1261/*
1262 * __stringify doesn't likes enums, so use SOCK_DCCP (6) and IPPROTO_DCCP (33)
1263 * values directly, Also cover the case where the protocol is not specified,
1264 * i.e. net-pf-PF_INET6-proto-0-type-SOCK_DCCP
1265 */
1266MODULE_ALIAS("net-pf-" __stringify(PF_INET6) "-proto-33-type-6");
1267MODULE_ALIAS("net-pf-" __stringify(PF_INET6) "-proto-0-type-6");
1268MODULE_LICENSE("GPL");
1269MODULE_AUTHOR("Arnaldo Carvalho de Melo <acme@mandriva.com>");
1270MODULE_DESCRIPTION("DCCPv6 - Datagram Congestion Controlled Protocol");