blob: ed4a502638023f40d5a8aa11d75cfda987c1a871 [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
61static inline u16 dccp_v6_check(struct dccp_hdr *dh, int len,
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -080062 struct in6_addr *saddr,
63 struct in6_addr *daddr,
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -080064 unsigned long base)
65{
66 return csum_ipv6_magic(saddr, daddr, len, IPPROTO_DCCP, base);
67}
68
69static __u32 dccp_v6_init_sequence(struct sock *sk, struct sk_buff *skb)
70{
71 const struct dccp_hdr *dh = dccp_hdr(skb);
72
73 if (skb->protocol == htons(ETH_P_IPV6))
74 return secure_tcpv6_sequence_number(skb->nh.ipv6h->daddr.s6_addr32,
75 skb->nh.ipv6h->saddr.s6_addr32,
76 dh->dccph_dport,
77 dh->dccph_sport);
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -080078
79 return secure_dccp_sequence_number(skb->nh.iph->daddr,
80 skb->nh.iph->saddr,
81 dh->dccph_dport,
82 dh->dccph_sport);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -080083}
84
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -080085static void dccp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
Andrea Bittau60fe62e2006-03-20 19:23:32 -080086 int type, int code, int offset, __be32 info)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -080087{
88 struct ipv6hdr *hdr = (struct ipv6hdr *)skb->data;
89 const struct dccp_hdr *dh = (struct dccp_hdr *)(skb->data + offset);
90 struct ipv6_pinfo *np;
91 struct sock *sk;
92 int err;
93 __u64 seq;
94
95 sk = inet6_lookup(&dccp_hashinfo, &hdr->daddr, dh->dccph_dport,
YOSHIFUJI Hideakif2776ff2006-11-21 17:41:56 -080096 &hdr->saddr, dh->dccph_sport, inet6_iif(skb));
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -080097
98 if (sk == NULL) {
99 ICMP6_INC_STATS_BH(__in6_dev_get(skb->dev), ICMP6_MIB_INERRORS);
100 return;
101 }
102
103 if (sk->sk_state == DCCP_TIME_WAIT) {
YOSHIFUJI Hideaki9469c7b2006-10-10 19:41:46 -0700104 inet_twsk_put(inet_twsk(sk));
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800105 return;
106 }
107
108 bh_lock_sock(sk);
109 if (sock_owned_by_user(sk))
110 NET_INC_STATS_BH(LINUX_MIB_LOCKDROPPEDICMPS);
111
112 if (sk->sk_state == DCCP_CLOSED)
113 goto out;
114
115 np = inet6_sk(sk);
116
117 if (type == ICMPV6_PKT_TOOBIG) {
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800118 struct dst_entry *dst = NULL;
119
120 if (sock_owned_by_user(sk))
121 goto out;
122 if ((1 << sk->sk_state) & (DCCPF_LISTEN | DCCPF_CLOSED))
123 goto out;
124
125 /* icmp should have updated the destination cache entry */
126 dst = __sk_dst_check(sk, np->dst_cookie);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800127 if (dst == NULL) {
128 struct inet_sock *inet = inet_sk(sk);
129 struct flowi fl;
130
131 /* BUGGG_FUTURE: Again, it is not clear how
132 to handle rthdr case. Ignore this complexity
133 for now.
134 */
135 memset(&fl, 0, sizeof(fl));
136 fl.proto = IPPROTO_DCCP;
137 ipv6_addr_copy(&fl.fl6_dst, &np->daddr);
138 ipv6_addr_copy(&fl.fl6_src, &np->saddr);
139 fl.oif = sk->sk_bound_dev_if;
140 fl.fl_ip_dport = inet->dport;
141 fl.fl_ip_sport = inet->sport;
Venkat Yekkiralabeb8d132006-08-04 23:12:42 -0700142 security_sk_classify_flow(sk, &fl);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800143
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800144 err = ip6_dst_lookup(sk, &dst, &fl);
145 if (err) {
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800146 sk->sk_err_soft = -err;
147 goto out;
148 }
149
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800150 err = xfrm_lookup(&dst, &fl, sk, 0);
151 if (err < 0) {
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800152 sk->sk_err_soft = -err;
153 goto out;
154 }
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800155 } else
156 dst_hold(dst);
157
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -0800158 if (inet_csk(sk)->icsk_pmtu_cookie > dst_mtu(dst)) {
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800159 dccp_sync_mss(sk, dst_mtu(dst));
160 } /* else let the usual retransmit timer handle it */
161 dst_release(dst);
162 goto out;
163 }
164
165 icmpv6_err_convert(type, code, &err);
166
167 seq = DCCP_SKB_CB(skb)->dccpd_seq;
168 /* Might be for an request_sock */
169 switch (sk->sk_state) {
170 struct request_sock *req, **prev;
171 case DCCP_LISTEN:
172 if (sock_owned_by_user(sk))
173 goto out;
174
175 req = inet6_csk_search_req(sk, &prev, dh->dccph_dport,
176 &hdr->daddr, &hdr->saddr,
177 inet6_iif(skb));
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800178 if (req == NULL)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800179 goto out;
180
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800181 /*
182 * ICMPs are not backlogged, hence we cannot get an established
183 * socket here.
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800184 */
185 BUG_TRAP(req->sk == NULL);
186
187 if (seq != dccp_rsk(req)->dreq_iss) {
188 NET_INC_STATS_BH(LINUX_MIB_OUTOFWINDOWICMPS);
189 goto out;
190 }
191
192 inet_csk_reqsk_queue_drop(sk, req, prev);
193 goto out;
194
195 case DCCP_REQUESTING:
196 case DCCP_RESPOND: /* Cannot happen.
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800197 It can, it SYNs are crossed. --ANK */
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800198 if (!sock_owned_by_user(sk)) {
199 DCCP_INC_STATS_BH(DCCP_MIB_ATTEMPTFAILS);
200 sk->sk_err = err;
201 /*
202 * Wake people up to see the error
203 * (see connect in sock.c)
204 */
205 sk->sk_error_report(sk);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800206 dccp_done(sk);
207 } else
208 sk->sk_err_soft = err;
209 goto out;
210 }
211
212 if (!sock_owned_by_user(sk) && np->recverr) {
213 sk->sk_err = err;
214 sk->sk_error_report(sk);
215 } else
216 sk->sk_err_soft = err;
217
218out:
219 bh_unlock_sock(sk);
220 sock_put(sk);
221}
222
223
224static int dccp_v6_send_response(struct sock *sk, struct request_sock *req,
225 struct dst_entry *dst)
226{
227 struct inet6_request_sock *ireq6 = inet6_rsk(req);
228 struct ipv6_pinfo *np = inet6_sk(sk);
229 struct sk_buff *skb;
230 struct ipv6_txoptions *opt = NULL;
231 struct in6_addr *final_p = NULL, final;
232 struct flowi fl;
233 int err = -1;
234
235 memset(&fl, 0, sizeof(fl));
236 fl.proto = IPPROTO_DCCP;
237 ipv6_addr_copy(&fl.fl6_dst, &ireq6->rmt_addr);
238 ipv6_addr_copy(&fl.fl6_src, &ireq6->loc_addr);
239 fl.fl6_flowlabel = 0;
240 fl.oif = ireq6->iif;
241 fl.fl_ip_dport = inet_rsk(req)->rmt_port;
242 fl.fl_ip_sport = inet_sk(sk)->sport;
Venkat Yekkirala4237c752006-07-24 23:32:50 -0700243 security_req_classify_flow(req, &fl);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800244
245 if (dst == NULL) {
246 opt = np->opt;
247 if (opt == NULL &&
248 np->rxopt.bits.osrcrt == 2 &&
249 ireq6->pktopts) {
250 struct sk_buff *pktopts = ireq6->pktopts;
251 struct inet6_skb_parm *rxopt = IP6CB(pktopts);
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800252
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800253 if (rxopt->srcrt)
254 opt = ipv6_invert_rthdr(sk,
255 (struct ipv6_rt_hdr *)(pktopts->nh.raw +
256 rxopt->srcrt));
257 }
258
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800259 if (opt != NULL && opt->srcrt != NULL) {
260 const struct rt0_hdr *rt0 = (struct rt0_hdr *)opt->srcrt;
261
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800262 ipv6_addr_copy(&final, &fl.fl6_dst);
263 ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
264 final_p = &final;
265 }
266
267 err = ip6_dst_lookup(sk, &dst, &fl);
268 if (err)
269 goto done;
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800270
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800271 if (final_p)
272 ipv6_addr_copy(&fl.fl6_dst, final_p);
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800273
274 err = xfrm_lookup(&dst, &fl, sk, 0);
275 if (err < 0)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800276 goto done;
277 }
278
279 skb = dccp_make_response(sk, dst, req);
280 if (skb != NULL) {
281 struct dccp_hdr *dh = dccp_hdr(skb);
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800282
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800283 dh->dccph_checksum = dccp_v6_check(dh, skb->len,
284 &ireq6->loc_addr,
285 &ireq6->rmt_addr,
286 csum_partial((char *)dh,
287 skb->len,
288 skb->csum));
289 ipv6_addr_copy(&fl.fl6_dst, &ireq6->rmt_addr);
290 err = ip6_xmit(sk, skb, &fl, opt, 0);
291 if (err == NET_XMIT_CN)
292 err = 0;
293 }
294
295done:
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800296 if (opt != NULL && opt != np->opt)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800297 sock_kfree_s(sk, opt, opt->tot_len);
David S. Miller0cbd7822006-01-31 17:53:37 -0800298 dst_release(dst);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800299 return err;
300}
301
302static void dccp_v6_reqsk_destructor(struct request_sock *req)
303{
304 if (inet6_rsk(req)->pktopts != NULL)
305 kfree_skb(inet6_rsk(req)->pktopts);
306}
307
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800308static void dccp_v6_send_check(struct sock *sk, int len, struct sk_buff *skb)
309{
310 struct ipv6_pinfo *np = inet6_sk(sk);
311 struct dccp_hdr *dh = dccp_hdr(skb);
312
313 dh->dccph_checksum = csum_ipv6_magic(&np->saddr, &np->daddr,
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800314 len, IPPROTO_DCCP,
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800315 csum_partial((char *)dh,
316 dh->dccph_doff << 2,
317 skb->csum));
318}
319
320static void dccp_v6_ctl_send_reset(struct sk_buff *rxskb)
321{
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800322 struct dccp_hdr *rxdh = dccp_hdr(rxskb), *dh;
Arnaldo Carvalho de Melo118b2c92006-03-20 22:31:09 -0800323 const u32 dccp_hdr_reset_len = sizeof(struct dccp_hdr) +
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800324 sizeof(struct dccp_hdr_ext) +
325 sizeof(struct dccp_hdr_reset);
326 struct sk_buff *skb;
327 struct flowi fl;
328 u64 seqno;
329
330 if (rxdh->dccph_type == DCCP_PKT_RESET)
331 return;
332
333 if (!ipv6_unicast_destination(rxskb))
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800334 return;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800335
Arnaldo Carvalho de Melo118b2c92006-03-20 22:31:09 -0800336 skb = alloc_skb(dccp_v6_ctl_socket->sk->sk_prot->max_header,
337 GFP_ATOMIC);
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800338 if (skb == NULL)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800339 return;
340
Arnaldo Carvalho de Melo118b2c92006-03-20 22:31:09 -0800341 skb_reserve(skb, dccp_v6_ctl_socket->sk->sk_prot->max_header);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800342
Gerrit Renker9b420782006-11-10 11:22:32 -0200343 dh = dccp_zeroed_hdr(skb, dccp_hdr_reset_len);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800344
345 /* Swap the send and the receive. */
346 dh->dccph_type = DCCP_PKT_RESET;
347 dh->dccph_sport = rxdh->dccph_dport;
348 dh->dccph_dport = rxdh->dccph_sport;
349 dh->dccph_doff = dccp_hdr_reset_len / 4;
350 dh->dccph_x = 1;
351 dccp_hdr_reset(skb)->dccph_reset_code =
352 DCCP_SKB_CB(rxskb)->dccpd_reset_code;
353
Gerrit Renker0e64e942006-10-24 16:17:51 -0700354 /* See "8.3.1. Abnormal Termination" in RFC 4340 */
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800355 seqno = 0;
356 if (DCCP_SKB_CB(rxskb)->dccpd_ack_seq != DCCP_PKT_WITHOUT_ACK_SEQ)
357 dccp_set_seqno(&seqno, DCCP_SKB_CB(rxskb)->dccpd_ack_seq + 1);
358
359 dccp_hdr_set_seq(dh, seqno);
360 dccp_hdr_set_ack(dccp_hdr_ack_bits(skb),
361 DCCP_SKB_CB(rxskb)->dccpd_seq);
362
363 memset(&fl, 0, sizeof(fl));
364 ipv6_addr_copy(&fl.fl6_dst, &rxskb->nh.ipv6h->saddr);
365 ipv6_addr_copy(&fl.fl6_src, &rxskb->nh.ipv6h->daddr);
366 dh->dccph_checksum = csum_ipv6_magic(&fl.fl6_src, &fl.fl6_dst,
367 sizeof(*dh), IPPROTO_DCCP,
368 skb->csum);
369 fl.proto = IPPROTO_DCCP;
370 fl.oif = inet6_iif(rxskb);
371 fl.fl_ip_dport = dh->dccph_dport;
372 fl.fl_ip_sport = dh->dccph_sport;
Venkat Yekkiralabeb8d132006-08-04 23:12:42 -0700373 security_skb_classify_flow(rxskb, &fl);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800374
375 /* sk = NULL, but it is safe for now. RST socket required. */
376 if (!ip6_dst_lookup(NULL, &skb->dst, &fl)) {
377 if (xfrm_lookup(&skb->dst, &fl, NULL, 0) >= 0) {
Arnaldo Carvalho de Melo72478872006-03-20 22:00:37 -0800378 ip6_xmit(dccp_v6_ctl_socket->sk, skb, &fl, NULL, 0);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800379 DCCP_INC_STATS_BH(DCCP_MIB_OUTSEGS);
380 DCCP_INC_STATS_BH(DCCP_MIB_OUTRSTS);
381 return;
382 }
383 }
384
385 kfree_skb(skb);
386}
387
Gerrit Renker73c9e022006-11-10 13:01:31 -0200388static struct request_sock_ops dccp6_request_sock_ops = {
389 .family = AF_INET6,
390 .obj_size = sizeof(struct dccp6_request_sock),
391 .rtx_syn_ack = dccp_v6_send_response,
392 .send_ack = dccp_reqsk_send_ack,
393 .destructor = dccp_v6_reqsk_destructor,
394 .send_reset = dccp_v6_ctl_send_reset,
395};
396
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800397static struct sock *dccp_v6_hnd_req(struct sock *sk,struct sk_buff *skb)
398{
399 const struct dccp_hdr *dh = dccp_hdr(skb);
400 const struct ipv6hdr *iph = skb->nh.ipv6h;
401 struct sock *nsk;
402 struct request_sock **prev;
403 /* Find possible connection requests. */
404 struct request_sock *req = inet6_csk_search_req(sk, &prev,
405 dh->dccph_sport,
406 &iph->saddr,
407 &iph->daddr,
408 inet6_iif(skb));
409 if (req != NULL)
410 return dccp_check_req(sk, skb, req, prev);
411
412 nsk = __inet6_lookup_established(&dccp_hashinfo,
413 &iph->saddr, dh->dccph_sport,
414 &iph->daddr, ntohs(dh->dccph_dport),
415 inet6_iif(skb));
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800416 if (nsk != NULL) {
417 if (nsk->sk_state != DCCP_TIME_WAIT) {
418 bh_lock_sock(nsk);
419 return nsk;
420 }
YOSHIFUJI Hideaki9469c7b2006-10-10 19:41:46 -0700421 inet_twsk_put(inet_twsk(nsk));
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800422 return NULL;
423 }
424
425 return sk;
426}
427
428static int dccp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
429{
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800430 struct dccp_sock dp;
431 struct request_sock *req;
432 struct dccp_request_sock *dreq;
433 struct inet6_request_sock *ireq6;
434 struct ipv6_pinfo *np = inet6_sk(sk);
Andrea Bittau60fe62e2006-03-20 19:23:32 -0800435 const __be32 service = dccp_hdr_request(skb)->dccph_req_service;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800436 struct dccp_skb_cb *dcb = DCCP_SKB_CB(skb);
437 __u8 reset_code = DCCP_RESET_CODE_TOO_BUSY;
438
439 if (skb->protocol == htons(ETH_P_IP))
440 return dccp_v4_conn_request(sk, skb);
441
442 if (!ipv6_unicast_destination(skb))
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800443 goto drop;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800444
445 if (dccp_bad_service_code(sk, service)) {
446 reset_code = DCCP_RESET_CODE_BAD_SERVICE_CODE;
447 goto drop;
448 }
449 /*
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800450 * There are no SYN attacks on IPv6, yet...
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800451 */
452 if (inet_csk_reqsk_queue_is_full(sk))
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800453 goto drop;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800454
455 if (sk_acceptq_is_full(sk) && inet_csk_reqsk_queue_young(sk) > 1)
456 goto drop;
457
Gerrit Renker82709532006-10-11 16:26:54 +0100458 req = inet6_reqsk_alloc(&dccp6_request_sock_ops);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800459 if (req == NULL)
460 goto drop;
461
462 /* FIXME: process options */
463
464 dccp_openreq_init(req, &dp, skb);
465
Venkat Yekkirala4237c752006-07-24 23:32:50 -0700466 if (security_inet_conn_request(sk, skb, req))
467 goto drop_and_free;
468
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800469 ireq6 = inet6_rsk(req);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800470 ipv6_addr_copy(&ireq6->rmt_addr, &skb->nh.ipv6h->saddr);
471 ipv6_addr_copy(&ireq6->loc_addr, &skb->nh.ipv6h->daddr);
Ian McDonald4b79f0a2006-07-23 23:33:28 -0700472 req->rcv_wnd = dccp_feat_default_sequence_window;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800473 ireq6->pktopts = NULL;
474
475 if (ipv6_opt_accepted(sk, skb) ||
476 np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo ||
477 np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim) {
478 atomic_inc(&skb->users);
479 ireq6->pktopts = skb;
480 }
481 ireq6->iif = sk->sk_bound_dev_if;
482
483 /* So that link locals have meaning */
484 if (!sk->sk_bound_dev_if &&
485 ipv6_addr_type(&ireq6->rmt_addr) & IPV6_ADDR_LINKLOCAL)
486 ireq6->iif = inet6_iif(skb);
487
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800488 /*
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800489 * Step 3: Process LISTEN state
490 *
491 * Set S.ISR, S.GSR, S.SWL, S.SWH from packet or Init Cookie
492 *
493 * In fact we defer setting S.GSR, S.SWL, S.SWH to
494 * dccp_create_openreq_child.
495 */
496 dreq = dccp_rsk(req);
497 dreq->dreq_isr = dcb->dccpd_seq;
498 dreq->dreq_iss = dccp_v6_init_sequence(sk, skb);
499 dreq->dreq_service = service;
500
501 if (dccp_v6_send_response(sk, req, NULL))
502 goto drop_and_free;
503
504 inet6_csk_reqsk_queue_hash_add(sk, req, DCCP_TIMEOUT_INIT);
505 return 0;
506
507drop_and_free:
508 reqsk_free(req);
509drop:
510 DCCP_INC_STATS_BH(DCCP_MIB_ATTEMPTFAILS);
511 dcb->dccpd_reset_code = reset_code;
512 return -1;
513}
514
515static struct sock *dccp_v6_request_recv_sock(struct sock *sk,
516 struct sk_buff *skb,
517 struct request_sock *req,
518 struct dst_entry *dst)
519{
520 struct inet6_request_sock *ireq6 = inet6_rsk(req);
521 struct ipv6_pinfo *newnp, *np = inet6_sk(sk);
522 struct inet_sock *newinet;
523 struct dccp_sock *newdp;
524 struct dccp6_sock *newdp6;
525 struct sock *newsk;
526 struct ipv6_txoptions *opt;
527
528 if (skb->protocol == htons(ETH_P_IP)) {
529 /*
530 * v6 mapped
531 */
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800532 newsk = dccp_v4_request_recv_sock(sk, skb, req, dst);
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800533 if (newsk == NULL)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800534 return NULL;
535
536 newdp6 = (struct dccp6_sock *)newsk;
537 newdp = dccp_sk(newsk);
538 newinet = inet_sk(newsk);
539 newinet->pinet6 = &newdp6->inet6;
540 newnp = inet6_sk(newsk);
541
542 memcpy(newnp, np, sizeof(struct ipv6_pinfo));
543
544 ipv6_addr_set(&newnp->daddr, 0, 0, htonl(0x0000FFFF),
545 newinet->daddr);
546
547 ipv6_addr_set(&newnp->saddr, 0, 0, htonl(0x0000FFFF),
548 newinet->saddr);
549
550 ipv6_addr_copy(&newnp->rcv_saddr, &newnp->saddr);
551
552 inet_csk(newsk)->icsk_af_ops = &dccp_ipv6_mapped;
553 newsk->sk_backlog_rcv = dccp_v4_do_rcv;
554 newnp->pktoptions = NULL;
555 newnp->opt = NULL;
556 newnp->mcast_oif = inet6_iif(skb);
557 newnp->mcast_hops = skb->nh.ipv6h->hop_limit;
558
559 /*
560 * No need to charge this sock to the relevant IPv6 refcnt debug socks count
561 * here, dccp_create_openreq_child now does this for us, see the comment in
562 * that function for the gory details. -acme
563 */
564
565 /* It is tricky place. Until this moment IPv4 tcp
566 worked with IPv6 icsk.icsk_af_ops.
567 Sync it now.
568 */
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -0800569 dccp_sync_mss(newsk, inet_csk(newsk)->icsk_pmtu_cookie);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800570
571 return newsk;
572 }
573
574 opt = np->opt;
575
576 if (sk_acceptq_is_full(sk))
577 goto out_overflow;
578
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800579 if (np->rxopt.bits.osrcrt == 2 && opt == NULL && ireq6->pktopts) {
580 const struct inet6_skb_parm *rxopt = IP6CB(ireq6->pktopts);
581
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800582 if (rxopt->srcrt)
583 opt = ipv6_invert_rthdr(sk,
584 (struct ipv6_rt_hdr *)(ireq6->pktopts->nh.raw +
585 rxopt->srcrt));
586 }
587
588 if (dst == NULL) {
589 struct in6_addr *final_p = NULL, final;
590 struct flowi fl;
591
592 memset(&fl, 0, sizeof(fl));
593 fl.proto = IPPROTO_DCCP;
594 ipv6_addr_copy(&fl.fl6_dst, &ireq6->rmt_addr);
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800595 if (opt != NULL && opt->srcrt != NULL) {
596 const struct rt0_hdr *rt0 = (struct rt0_hdr *)opt->srcrt;
597
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800598 ipv6_addr_copy(&final, &fl.fl6_dst);
599 ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
600 final_p = &final;
601 }
602 ipv6_addr_copy(&fl.fl6_src, &ireq6->loc_addr);
603 fl.oif = sk->sk_bound_dev_if;
604 fl.fl_ip_dport = inet_rsk(req)->rmt_port;
605 fl.fl_ip_sport = inet_sk(sk)->sport;
Venkat Yekkiralabeb8d132006-08-04 23:12:42 -0700606 security_sk_classify_flow(sk, &fl);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800607
608 if (ip6_dst_lookup(sk, &dst, &fl))
609 goto out;
610
611 if (final_p)
612 ipv6_addr_copy(&fl.fl6_dst, final_p);
613
614 if ((xfrm_lookup(&dst, &fl, sk, 0)) < 0)
615 goto out;
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800616 }
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800617
618 newsk = dccp_create_openreq_child(sk, req, skb);
619 if (newsk == NULL)
620 goto out;
621
622 /*
623 * No need to charge this sock to the relevant IPv6 refcnt debug socks
624 * count here, dccp_create_openreq_child now does this for us, see the
625 * comment in that function for the gory details. -acme
626 */
627
YOSHIFUJI Hideaki8e1ef0a2006-08-29 17:15:09 -0700628 __ip6_dst_store(newsk, dst, NULL, NULL);
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800629 newsk->sk_route_caps = dst->dev->features & ~(NETIF_F_IP_CSUM |
630 NETIF_F_TSO);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800631 newdp6 = (struct dccp6_sock *)newsk;
632 newinet = inet_sk(newsk);
633 newinet->pinet6 = &newdp6->inet6;
634 newdp = dccp_sk(newsk);
635 newnp = inet6_sk(newsk);
636
637 memcpy(newnp, np, sizeof(struct ipv6_pinfo));
638
639 ipv6_addr_copy(&newnp->daddr, &ireq6->rmt_addr);
640 ipv6_addr_copy(&newnp->saddr, &ireq6->loc_addr);
641 ipv6_addr_copy(&newnp->rcv_saddr, &ireq6->loc_addr);
642 newsk->sk_bound_dev_if = ireq6->iif;
643
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800644 /* Now IPv6 options...
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800645
646 First: no IPv4 options.
647 */
648 newinet->opt = NULL;
649
650 /* Clone RX bits */
651 newnp->rxopt.all = np->rxopt.all;
652
653 /* Clone pktoptions received with SYN */
654 newnp->pktoptions = NULL;
655 if (ireq6->pktopts != NULL) {
656 newnp->pktoptions = skb_clone(ireq6->pktopts, GFP_ATOMIC);
657 kfree_skb(ireq6->pktopts);
658 ireq6->pktopts = NULL;
659 if (newnp->pktoptions)
660 skb_set_owner_r(newnp->pktoptions, newsk);
661 }
662 newnp->opt = NULL;
663 newnp->mcast_oif = inet6_iif(skb);
664 newnp->mcast_hops = skb->nh.ipv6h->hop_limit;
665
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800666 /*
667 * Clone native IPv6 options from listening socket (if any)
668 *
669 * Yes, keeping reference count would be much more clever, but we make
670 * one more one thing there: reattach optmem to newsk.
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800671 */
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800672 if (opt != NULL) {
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800673 newnp->opt = ipv6_dup_options(newsk, opt);
674 if (opt != np->opt)
675 sock_kfree_s(sk, opt, opt->tot_len);
676 }
677
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -0800678 inet_csk(newsk)->icsk_ext_hdr_len = 0;
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800679 if (newnp->opt != NULL)
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -0800680 inet_csk(newsk)->icsk_ext_hdr_len = (newnp->opt->opt_nflen +
681 newnp->opt->opt_flen);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800682
683 dccp_sync_mss(newsk, dst_mtu(dst));
684
685 newinet->daddr = newinet->saddr = newinet->rcv_saddr = LOOPBACK4_IPV6;
686
687 __inet6_hash(&dccp_hashinfo, newsk);
688 inet_inherit_port(&dccp_hashinfo, sk, newsk);
689
690 return newsk;
691
692out_overflow:
693 NET_INC_STATS_BH(LINUX_MIB_LISTENOVERFLOWS);
694out:
695 NET_INC_STATS_BH(LINUX_MIB_LISTENDROPS);
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800696 if (opt != NULL && opt != np->opt)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800697 sock_kfree_s(sk, opt, opt->tot_len);
698 dst_release(dst);
699 return NULL;
700}
701
702/* The socket must have it's spinlock held when we get
703 * here.
704 *
705 * We have a potential double-lock case here, so even when
706 * doing backlog processing we use the BH locking scheme.
707 * This is because we cannot sleep with the original spinlock
708 * held.
709 */
710static int dccp_v6_do_rcv(struct sock *sk, struct sk_buff *skb)
711{
712 struct ipv6_pinfo *np = inet6_sk(sk);
713 struct sk_buff *opt_skb = NULL;
714
715 /* Imagine: socket is IPv6. IPv4 packet arrives,
716 goes to IPv4 receive handler and backlogged.
717 From backlog it always goes here. Kerboom...
718 Fortunately, dccp_rcv_established and rcv_established
719 handle them correctly, but it is not case with
720 dccp_v6_hnd_req and dccp_v6_ctl_send_reset(). --ANK
721 */
722
723 if (skb->protocol == htons(ETH_P_IP))
724 return dccp_v4_do_rcv(sk, skb);
725
Dmitry Mishinfda9ef52006-08-31 15:28:39 -0700726 if (sk_filter(sk, skb))
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800727 goto discard;
728
729 /*
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800730 * socket locking is here for SMP purposes as backlog rcv is currently
731 * called with bh processing disabled.
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800732 */
733
734 /* Do Stevens' IPV6_PKTOPTIONS.
735
736 Yes, guys, it is the only place in our code, where we
737 may make it not affecting IPv4.
738 The rest of code is protocol independent,
739 and I do not like idea to uglify IPv4.
740
741 Actually, all the idea behind IPV6_PKTOPTIONS
742 looks not very well thought. For now we latch
743 options, received in the last packet, enqueued
744 by tcp. Feel free to propose better solution.
745 --ANK (980728)
746 */
747 if (np->rxopt.all)
Gerrit Renker89e7e572006-11-10 11:13:33 -0200748 /*
749 * FIXME: Add handling of IPV6_PKTOPTIONS skb. See the comments below
750 * (wrt ipv6_pktopions) and net/ipv6/tcp_ipv6.c for an example.
751 */
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800752 opt_skb = skb_clone(skb, GFP_ATOMIC);
753
754 if (sk->sk_state == DCCP_OPEN) { /* Fast path */
755 if (dccp_rcv_established(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 }
763
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800764 if (sk->sk_state == DCCP_LISTEN) {
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800765 struct sock *nsk = dccp_v6_hnd_req(sk, skb);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800766
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800767 if (nsk == NULL)
768 goto discard;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800769 /*
770 * Queue it on the new socket if the new socket is active,
771 * otherwise we just shortcircuit this and continue with
772 * the new socket..
773 */
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800774 if (nsk != sk) {
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800775 if (dccp_child_process(sk, nsk, skb))
776 goto reset;
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800777 if (opt_skb != NULL)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800778 __kfree_skb(opt_skb);
779 return 0;
780 }
781 }
782
783 if (dccp_rcv_state_process(sk, skb, dccp_hdr(skb), skb->len))
784 goto reset;
David S. Millerfd169f12006-10-20 19:44:17 -0700785 if (opt_skb) {
Gerrit Renker89e7e572006-11-10 11:13:33 -0200786 /* XXX This is where we would goto ipv6_pktoptions. */
David S. Millerfd169f12006-10-20 19:44:17 -0700787 __kfree_skb(opt_skb);
788 }
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800789 return 0;
790
791reset:
792 dccp_v6_ctl_send_reset(skb);
793discard:
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800794 if (opt_skb != NULL)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800795 __kfree_skb(opt_skb);
796 kfree_skb(skb);
797 return 0;
798}
799
Patrick McHardy951dbc82006-01-06 23:02:34 -0800800static int dccp_v6_rcv(struct sk_buff **pskb)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800801{
802 const struct dccp_hdr *dh;
803 struct sk_buff *skb = *pskb;
804 struct sock *sk;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800805
806 /* Step 1: Check header basics: */
807
808 if (dccp_invalid_packet(skb))
809 goto discard_it;
810
811 dh = dccp_hdr(skb);
812
813 DCCP_SKB_CB(skb)->dccpd_seq = dccp_hdr_seq(skb);
814 DCCP_SKB_CB(skb)->dccpd_type = dh->dccph_type;
815
816 if (dccp_packet_without_ack(skb))
817 DCCP_SKB_CB(skb)->dccpd_ack_seq = DCCP_PKT_WITHOUT_ACK_SEQ;
818 else
819 DCCP_SKB_CB(skb)->dccpd_ack_seq = dccp_hdr_ack_seq(skb);
820
821 /* Step 2:
822 * Look up flow ID in table and get corresponding socket */
823 sk = __inet6_lookup(&dccp_hashinfo, &skb->nh.ipv6h->saddr,
824 dh->dccph_sport,
825 &skb->nh.ipv6h->daddr, ntohs(dh->dccph_dport),
826 inet6_iif(skb));
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800827 /*
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800828 * Step 2:
829 * If no socket ...
830 * Generate Reset(No Connection) unless P.type == Reset
831 * Drop packet and return
832 */
Gerrit Renkerd23c7102006-11-10 11:46:34 -0200833 if (sk == NULL) {
834 dccp_pr_debug("failed to look up flow ID in table and "
835 "get corresponding socket\n");
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800836 goto no_dccp_socket;
Gerrit Renkerd23c7102006-11-10 11:46:34 -0200837 }
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800838
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800839 /*
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800840 * Step 2:
841 * ... or S.state == TIMEWAIT,
842 * Generate Reset(No Connection) unless P.type == Reset
843 * Drop packet and return
844 */
Gerrit Renkerd23c7102006-11-10 11:46:34 -0200845 if (sk->sk_state == DCCP_TIME_WAIT) {
846 dccp_pr_debug("sk->sk_state == DCCP_TIME_WAIT: do_time_wait\n");
847 inet_twsk_put(inet_twsk(sk));
848 goto no_dccp_socket;
849 }
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800850
851 if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb))
852 goto discard_and_relse;
853
Arnaldo Carvalho de Melo25995ff2005-12-27 02:42:22 -0200854 return sk_receive_skb(sk, skb) ? -1 : 0;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800855
856no_dccp_socket:
857 if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb))
858 goto discard_it;
859 /*
860 * Step 2:
861 * Generate Reset(No Connection) unless P.type == Reset
862 * Drop packet and return
863 */
864 if (dh->dccph_type != DCCP_PKT_RESET) {
865 DCCP_SKB_CB(skb)->dccpd_reset_code =
866 DCCP_RESET_CODE_NO_CONNECTION;
867 dccp_v6_ctl_send_reset(skb);
868 }
Gerrit Renkerd23c7102006-11-10 11:46:34 -0200869
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800870discard_it:
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800871 kfree_skb(skb);
872 return 0;
873
874discard_and_relse:
875 sock_put(sk);
876 goto discard_it;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800877}
878
Gerrit Renker73c9e022006-11-10 13:01:31 -0200879static int dccp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
880 int addr_len)
881{
882 struct sockaddr_in6 *usin = (struct sockaddr_in6 *)uaddr;
883 struct inet_connection_sock *icsk = inet_csk(sk);
884 struct inet_sock *inet = inet_sk(sk);
885 struct ipv6_pinfo *np = inet6_sk(sk);
886 struct dccp_sock *dp = dccp_sk(sk);
887 struct in6_addr *saddr = NULL, *final_p = NULL, final;
888 struct flowi fl;
889 struct dst_entry *dst;
890 int addr_type;
891 int err;
892
893 dp->dccps_role = DCCP_ROLE_CLIENT;
894
895 if (addr_len < SIN6_LEN_RFC2133)
896 return -EINVAL;
897
898 if (usin->sin6_family != AF_INET6)
899 return -EAFNOSUPPORT;
900
901 memset(&fl, 0, sizeof(fl));
902
903 if (np->sndflow) {
904 fl.fl6_flowlabel = usin->sin6_flowinfo & IPV6_FLOWINFO_MASK;
905 IP6_ECN_flow_init(fl.fl6_flowlabel);
906 if (fl.fl6_flowlabel & IPV6_FLOWLABEL_MASK) {
907 struct ip6_flowlabel *flowlabel;
908 flowlabel = fl6_sock_lookup(sk, fl.fl6_flowlabel);
909 if (flowlabel == NULL)
910 return -EINVAL;
911 ipv6_addr_copy(&usin->sin6_addr, &flowlabel->dst);
912 fl6_sock_release(flowlabel);
913 }
914 }
915 /*
916 * connect() to INADDR_ANY means loopback (BSD'ism).
917 */
918 if (ipv6_addr_any(&usin->sin6_addr))
919 usin->sin6_addr.s6_addr[15] = 1;
920
921 addr_type = ipv6_addr_type(&usin->sin6_addr);
922
923 if (addr_type & IPV6_ADDR_MULTICAST)
924 return -ENETUNREACH;
925
926 if (addr_type & IPV6_ADDR_LINKLOCAL) {
927 if (addr_len >= sizeof(struct sockaddr_in6) &&
928 usin->sin6_scope_id) {
929 /* If interface is set while binding, indices
930 * must coincide.
931 */
932 if (sk->sk_bound_dev_if &&
933 sk->sk_bound_dev_if != usin->sin6_scope_id)
934 return -EINVAL;
935
936 sk->sk_bound_dev_if = usin->sin6_scope_id;
937 }
938
939 /* Connect to link-local address requires an interface */
940 if (!sk->sk_bound_dev_if)
941 return -EINVAL;
942 }
943
944 ipv6_addr_copy(&np->daddr, &usin->sin6_addr);
945 np->flow_label = fl.fl6_flowlabel;
946
947 /*
948 * DCCP over IPv4
949 */
950 if (addr_type == IPV6_ADDR_MAPPED) {
951 u32 exthdrlen = icsk->icsk_ext_hdr_len;
952 struct sockaddr_in sin;
953
954 SOCK_DEBUG(sk, "connect: ipv4 mapped\n");
955
956 if (__ipv6_only_sock(sk))
957 return -ENETUNREACH;
958
959 sin.sin_family = AF_INET;
960 sin.sin_port = usin->sin6_port;
961 sin.sin_addr.s_addr = usin->sin6_addr.s6_addr32[3];
962
963 icsk->icsk_af_ops = &dccp_ipv6_mapped;
964 sk->sk_backlog_rcv = dccp_v4_do_rcv;
965
966 err = dccp_v4_connect(sk, (struct sockaddr *)&sin, sizeof(sin));
967 if (err) {
968 icsk->icsk_ext_hdr_len = exthdrlen;
969 icsk->icsk_af_ops = &dccp_ipv6_af_ops;
970 sk->sk_backlog_rcv = dccp_v6_do_rcv;
971 goto failure;
972 } else {
973 ipv6_addr_set(&np->saddr, 0, 0, htonl(0x0000FFFF),
974 inet->saddr);
975 ipv6_addr_set(&np->rcv_saddr, 0, 0, htonl(0x0000FFFF),
976 inet->rcv_saddr);
977 }
978
979 return err;
980 }
981
982 if (!ipv6_addr_any(&np->rcv_saddr))
983 saddr = &np->rcv_saddr;
984
985 fl.proto = IPPROTO_DCCP;
986 ipv6_addr_copy(&fl.fl6_dst, &np->daddr);
987 ipv6_addr_copy(&fl.fl6_src, saddr ? saddr : &np->saddr);
988 fl.oif = sk->sk_bound_dev_if;
989 fl.fl_ip_dport = usin->sin6_port;
990 fl.fl_ip_sport = inet->sport;
991 security_sk_classify_flow(sk, &fl);
992
993 if (np->opt != NULL && np->opt->srcrt != NULL) {
994 const struct rt0_hdr *rt0 = (struct rt0_hdr *)np->opt->srcrt;
995
996 ipv6_addr_copy(&final, &fl.fl6_dst);
997 ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
998 final_p = &final;
999 }
1000
1001 err = ip6_dst_lookup(sk, &dst, &fl);
1002 if (err)
1003 goto failure;
1004
1005 if (final_p)
1006 ipv6_addr_copy(&fl.fl6_dst, final_p);
1007
1008 err = xfrm_lookup(&dst, &fl, sk, 0);
1009 if (err < 0)
1010 goto failure;
1011
1012 if (saddr == NULL) {
1013 saddr = &fl.fl6_src;
1014 ipv6_addr_copy(&np->rcv_saddr, saddr);
1015 }
1016
1017 /* set the source address */
1018 ipv6_addr_copy(&np->saddr, saddr);
1019 inet->rcv_saddr = LOOPBACK4_IPV6;
1020
1021 __ip6_dst_store(sk, dst, NULL, NULL);
1022
1023 icsk->icsk_ext_hdr_len = 0;
1024 if (np->opt != NULL)
1025 icsk->icsk_ext_hdr_len = (np->opt->opt_flen +
1026 np->opt->opt_nflen);
1027
1028 inet->dport = usin->sin6_port;
1029
1030 dccp_set_state(sk, DCCP_REQUESTING);
1031 err = inet6_hash_connect(&dccp_death_row, sk);
1032 if (err)
1033 goto late_failure;
1034 /* FIXME */
1035#if 0
1036 dp->dccps_gar = secure_dccp_v6_sequence_number(np->saddr.s6_addr32,
1037 np->daddr.s6_addr32,
1038 inet->sport,
1039 inet->dport);
1040#endif
1041 err = dccp_connect(sk);
1042 if (err)
1043 goto late_failure;
1044
1045 return 0;
1046
1047late_failure:
1048 dccp_set_state(sk, DCCP_CLOSED);
1049 __sk_dst_reset(sk);
1050failure:
1051 inet->dport = 0;
1052 sk->sk_route_caps = 0;
1053 return err;
1054}
1055
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001056static struct inet_connection_sock_af_ops dccp_ipv6_af_ops = {
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001057 .queue_xmit = inet6_csk_xmit,
1058 .send_check = dccp_v6_send_check,
1059 .rebuild_header = inet6_sk_rebuild_header,
1060 .conn_request = dccp_v6_conn_request,
1061 .syn_recv_sock = dccp_v6_request_recv_sock,
1062 .net_header_len = sizeof(struct ipv6hdr),
1063 .setsockopt = ipv6_setsockopt,
1064 .getsockopt = ipv6_getsockopt,
1065 .addr2sockaddr = inet6_csk_addr2sockaddr,
1066 .sockaddr_len = sizeof(struct sockaddr_in6),
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001067#ifdef CONFIG_COMPAT
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001068 .compat_setsockopt = compat_ipv6_setsockopt,
1069 .compat_getsockopt = compat_ipv6_getsockopt,
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001070#endif
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001071};
1072
1073/*
1074 * DCCP over IPv4 via INET6 API
1075 */
1076static struct inet_connection_sock_af_ops dccp_ipv6_mapped = {
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001077 .queue_xmit = ip_queue_xmit,
1078 .send_check = dccp_v4_send_check,
1079 .rebuild_header = inet_sk_rebuild_header,
1080 .conn_request = dccp_v6_conn_request,
1081 .syn_recv_sock = dccp_v6_request_recv_sock,
1082 .net_header_len = sizeof(struct iphdr),
1083 .setsockopt = ipv6_setsockopt,
1084 .getsockopt = ipv6_getsockopt,
1085 .addr2sockaddr = inet6_csk_addr2sockaddr,
1086 .sockaddr_len = sizeof(struct sockaddr_in6),
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001087#ifdef CONFIG_COMPAT
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001088 .compat_setsockopt = compat_ipv6_setsockopt,
1089 .compat_getsockopt = compat_ipv6_getsockopt,
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001090#endif
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001091};
1092
1093/* NOTE: A lot of things set to zero explicitly by call to
1094 * sk_alloc() so need not be done here.
1095 */
1096static int dccp_v6_init_sock(struct sock *sk)
1097{
Arnaldo Carvalho de Melo72478872006-03-20 22:00:37 -08001098 static __u8 dccp_v6_ctl_sock_initialized;
1099 int err = dccp_init_sock(sk, dccp_v6_ctl_sock_initialized);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001100
Arnaldo Carvalho de Melo72478872006-03-20 22:00:37 -08001101 if (err == 0) {
1102 if (unlikely(!dccp_v6_ctl_sock_initialized))
1103 dccp_v6_ctl_sock_initialized = 1;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001104 inet_csk(sk)->icsk_af_ops = &dccp_ipv6_af_ops;
Arnaldo Carvalho de Melo72478872006-03-20 22:00:37 -08001105 }
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001106
1107 return err;
1108}
1109
1110static int dccp_v6_destroy_sock(struct sock *sk)
1111{
Arnaldo Carvalho de Melo3e0fadc2006-03-20 21:23:15 -08001112 dccp_destroy_sock(sk);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001113 return inet6_destroy_sock(sk);
1114}
1115
Gerrit Renker73c9e022006-11-10 13:01:31 -02001116static struct timewait_sock_ops dccp6_timewait_sock_ops = {
1117 .twsk_obj_size = sizeof(struct dccp6_timewait_sock),
1118};
1119
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001120static struct proto dccp_v6_prot = {
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001121 .name = "DCCPv6",
1122 .owner = THIS_MODULE,
1123 .close = dccp_close,
1124 .connect = dccp_v6_connect,
1125 .disconnect = dccp_disconnect,
1126 .ioctl = dccp_ioctl,
1127 .init = dccp_v6_init_sock,
1128 .setsockopt = dccp_setsockopt,
1129 .getsockopt = dccp_getsockopt,
1130 .sendmsg = dccp_sendmsg,
1131 .recvmsg = dccp_recvmsg,
1132 .backlog_rcv = dccp_v6_do_rcv,
1133 .hash = dccp_v6_hash,
1134 .unhash = dccp_unhash,
1135 .accept = inet_csk_accept,
1136 .get_port = dccp_v6_get_port,
1137 .shutdown = dccp_shutdown,
1138 .destroy = dccp_v6_destroy_sock,
1139 .orphan_count = &dccp_orphan_count,
1140 .max_header = MAX_DCCP_HEADER,
1141 .obj_size = sizeof(struct dccp6_sock),
1142 .rsk_prot = &dccp6_request_sock_ops,
1143 .twsk_prot = &dccp6_timewait_sock_ops,
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001144#ifdef CONFIG_COMPAT
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001145 .compat_setsockopt = compat_dccp_setsockopt,
1146 .compat_getsockopt = compat_dccp_getsockopt,
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001147#endif
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001148};
1149
1150static struct inet6_protocol dccp_v6_protocol = {
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -08001151 .handler = dccp_v6_rcv,
1152 .err_handler = dccp_v6_err,
1153 .flags = INET6_PROTO_NOPOLICY | INET6_PROTO_FINAL,
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001154};
1155
1156static struct proto_ops inet6_dccp_ops = {
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001157 .family = PF_INET6,
1158 .owner = THIS_MODULE,
1159 .release = inet6_release,
1160 .bind = inet6_bind,
1161 .connect = inet_stream_connect,
1162 .socketpair = sock_no_socketpair,
1163 .accept = inet_accept,
1164 .getname = inet6_getname,
1165 .poll = dccp_poll,
1166 .ioctl = inet6_ioctl,
1167 .listen = inet_dccp_listen,
1168 .shutdown = inet_shutdown,
1169 .setsockopt = sock_common_setsockopt,
1170 .getsockopt = sock_common_getsockopt,
1171 .sendmsg = inet_sendmsg,
1172 .recvmsg = sock_common_recvmsg,
1173 .mmap = sock_no_mmap,
1174 .sendpage = sock_no_sendpage,
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001175#ifdef CONFIG_COMPAT
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001176 .compat_setsockopt = compat_sock_common_setsockopt,
1177 .compat_getsockopt = compat_sock_common_getsockopt,
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001178#endif
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001179};
1180
1181static struct inet_protosw dccp_v6_protosw = {
1182 .type = SOCK_DCCP,
1183 .protocol = IPPROTO_DCCP,
1184 .prot = &dccp_v6_prot,
1185 .ops = &inet6_dccp_ops,
1186 .capability = -1,
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -08001187 .flags = INET_PROTOSW_ICSK,
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001188};
1189
1190static int __init dccp_v6_init(void)
1191{
1192 int err = proto_register(&dccp_v6_prot, 1);
1193
1194 if (err != 0)
1195 goto out;
1196
1197 err = inet6_add_protocol(&dccp_v6_protocol, IPPROTO_DCCP);
1198 if (err != 0)
1199 goto out_unregister_proto;
1200
1201 inet6_register_protosw(&dccp_v6_protosw);
Arnaldo Carvalho de Melo72478872006-03-20 22:00:37 -08001202
Arnaldo Carvalho de Meloc4d93902006-03-20 22:01:03 -08001203 err = inet_csk_ctl_sock_create(&dccp_v6_ctl_socket, PF_INET6,
1204 SOCK_DCCP, IPPROTO_DCCP);
1205 if (err != 0)
Arnaldo Carvalho de Melo72478872006-03-20 22:00:37 -08001206 goto out_unregister_protosw;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001207out:
1208 return err;
Arnaldo Carvalho de Melo72478872006-03-20 22:00:37 -08001209out_unregister_protosw:
1210 inet6_del_protocol(&dccp_v6_protocol, IPPROTO_DCCP);
1211 inet6_unregister_protosw(&dccp_v6_protosw);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001212out_unregister_proto:
1213 proto_unregister(&dccp_v6_prot);
1214 goto out;
1215}
1216
1217static void __exit dccp_v6_exit(void)
1218{
1219 inet6_del_protocol(&dccp_v6_protocol, IPPROTO_DCCP);
1220 inet6_unregister_protosw(&dccp_v6_protosw);
1221 proto_unregister(&dccp_v6_prot);
1222}
1223
1224module_init(dccp_v6_init);
1225module_exit(dccp_v6_exit);
1226
1227/*
1228 * __stringify doesn't likes enums, so use SOCK_DCCP (6) and IPPROTO_DCCP (33)
1229 * values directly, Also cover the case where the protocol is not specified,
1230 * i.e. net-pf-PF_INET6-proto-0-type-SOCK_DCCP
1231 */
1232MODULE_ALIAS("net-pf-" __stringify(PF_INET6) "-proto-33-type-6");
1233MODULE_ALIAS("net-pf-" __stringify(PF_INET6) "-proto-0-type-6");
1234MODULE_LICENSE("GPL");
1235MODULE_AUTHOR("Arnaldo Carvalho de Melo <acme@mandriva.com>");
1236MODULE_DESCRIPTION("DCCPv6 - Datagram Congestion Controlled Protocol");