blob: 19a4f763099d81036027fc36ed4bc5d53152442b [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 request_sock *req;
431 struct dccp_request_sock *dreq;
432 struct inet6_request_sock *ireq6;
433 struct ipv6_pinfo *np = inet6_sk(sk);
Andrea Bittau60fe62e2006-03-20 19:23:32 -0800434 const __be32 service = dccp_hdr_request(skb)->dccph_req_service;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800435 struct dccp_skb_cb *dcb = DCCP_SKB_CB(skb);
436 __u8 reset_code = DCCP_RESET_CODE_TOO_BUSY;
437
438 if (skb->protocol == htons(ETH_P_IP))
439 return dccp_v4_conn_request(sk, skb);
440
441 if (!ipv6_unicast_destination(skb))
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800442 goto drop;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800443
444 if (dccp_bad_service_code(sk, service)) {
445 reset_code = DCCP_RESET_CODE_BAD_SERVICE_CODE;
446 goto drop;
447 }
448 /*
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800449 * There are no SYN attacks on IPv6, yet...
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800450 */
451 if (inet_csk_reqsk_queue_is_full(sk))
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800452 goto drop;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800453
454 if (sk_acceptq_is_full(sk) && inet_csk_reqsk_queue_young(sk) > 1)
455 goto drop;
456
Gerrit Renker82709532006-10-11 16:26:54 +0100457 req = inet6_reqsk_alloc(&dccp6_request_sock_ops);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800458 if (req == NULL)
459 goto drop;
460
Gerrit Renkercf557922006-11-10 16:08:37 -0200461 if (dccp_parse_options(sk, skb))
462 goto drop_and_free;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800463
Gerrit Renkercf557922006-11-10 16:08:37 -0200464 dccp_reqsk_init(req, skb);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800465
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);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800472 ireq6->pktopts = NULL;
473
474 if (ipv6_opt_accepted(sk, skb) ||
475 np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo ||
476 np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim) {
477 atomic_inc(&skb->users);
478 ireq6->pktopts = skb;
479 }
480 ireq6->iif = sk->sk_bound_dev_if;
481
482 /* So that link locals have meaning */
483 if (!sk->sk_bound_dev_if &&
484 ipv6_addr_type(&ireq6->rmt_addr) & IPV6_ADDR_LINKLOCAL)
485 ireq6->iif = inet6_iif(skb);
486
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800487 /*
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800488 * Step 3: Process LISTEN state
489 *
490 * Set S.ISR, S.GSR, S.SWL, S.SWH from packet or Init Cookie
491 *
492 * In fact we defer setting S.GSR, S.SWL, S.SWH to
493 * dccp_create_openreq_child.
494 */
495 dreq = dccp_rsk(req);
496 dreq->dreq_isr = dcb->dccpd_seq;
497 dreq->dreq_iss = dccp_v6_init_sequence(sk, skb);
498 dreq->dreq_service = service;
499
500 if (dccp_v6_send_response(sk, req, NULL))
501 goto drop_and_free;
502
503 inet6_csk_reqsk_queue_hash_add(sk, req, DCCP_TIMEOUT_INIT);
504 return 0;
505
506drop_and_free:
507 reqsk_free(req);
508drop:
509 DCCP_INC_STATS_BH(DCCP_MIB_ATTEMPTFAILS);
510 dcb->dccpd_reset_code = reset_code;
511 return -1;
512}
513
514static struct sock *dccp_v6_request_recv_sock(struct sock *sk,
515 struct sk_buff *skb,
516 struct request_sock *req,
517 struct dst_entry *dst)
518{
519 struct inet6_request_sock *ireq6 = inet6_rsk(req);
520 struct ipv6_pinfo *newnp, *np = inet6_sk(sk);
521 struct inet_sock *newinet;
522 struct dccp_sock *newdp;
523 struct dccp6_sock *newdp6;
524 struct sock *newsk;
525 struct ipv6_txoptions *opt;
526
527 if (skb->protocol == htons(ETH_P_IP)) {
528 /*
529 * v6 mapped
530 */
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800531 newsk = dccp_v4_request_recv_sock(sk, skb, req, dst);
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800532 if (newsk == NULL)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800533 return NULL;
534
535 newdp6 = (struct dccp6_sock *)newsk;
536 newdp = dccp_sk(newsk);
537 newinet = inet_sk(newsk);
538 newinet->pinet6 = &newdp6->inet6;
539 newnp = inet6_sk(newsk);
540
541 memcpy(newnp, np, sizeof(struct ipv6_pinfo));
542
543 ipv6_addr_set(&newnp->daddr, 0, 0, htonl(0x0000FFFF),
544 newinet->daddr);
545
546 ipv6_addr_set(&newnp->saddr, 0, 0, htonl(0x0000FFFF),
547 newinet->saddr);
548
549 ipv6_addr_copy(&newnp->rcv_saddr, &newnp->saddr);
550
551 inet_csk(newsk)->icsk_af_ops = &dccp_ipv6_mapped;
552 newsk->sk_backlog_rcv = dccp_v4_do_rcv;
553 newnp->pktoptions = NULL;
554 newnp->opt = NULL;
555 newnp->mcast_oif = inet6_iif(skb);
556 newnp->mcast_hops = skb->nh.ipv6h->hop_limit;
557
558 /*
559 * No need to charge this sock to the relevant IPv6 refcnt debug socks count
560 * here, dccp_create_openreq_child now does this for us, see the comment in
561 * that function for the gory details. -acme
562 */
563
564 /* It is tricky place. Until this moment IPv4 tcp
565 worked with IPv6 icsk.icsk_af_ops.
566 Sync it now.
567 */
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -0800568 dccp_sync_mss(newsk, inet_csk(newsk)->icsk_pmtu_cookie);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800569
570 return newsk;
571 }
572
573 opt = np->opt;
574
575 if (sk_acceptq_is_full(sk))
576 goto out_overflow;
577
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800578 if (np->rxopt.bits.osrcrt == 2 && opt == NULL && ireq6->pktopts) {
579 const struct inet6_skb_parm *rxopt = IP6CB(ireq6->pktopts);
580
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800581 if (rxopt->srcrt)
582 opt = ipv6_invert_rthdr(sk,
583 (struct ipv6_rt_hdr *)(ireq6->pktopts->nh.raw +
584 rxopt->srcrt));
585 }
586
587 if (dst == NULL) {
588 struct in6_addr *final_p = NULL, final;
589 struct flowi fl;
590
591 memset(&fl, 0, sizeof(fl));
592 fl.proto = IPPROTO_DCCP;
593 ipv6_addr_copy(&fl.fl6_dst, &ireq6->rmt_addr);
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800594 if (opt != NULL && opt->srcrt != NULL) {
595 const struct rt0_hdr *rt0 = (struct rt0_hdr *)opt->srcrt;
596
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800597 ipv6_addr_copy(&final, &fl.fl6_dst);
598 ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
599 final_p = &final;
600 }
601 ipv6_addr_copy(&fl.fl6_src, &ireq6->loc_addr);
602 fl.oif = sk->sk_bound_dev_if;
603 fl.fl_ip_dport = inet_rsk(req)->rmt_port;
604 fl.fl_ip_sport = inet_sk(sk)->sport;
Venkat Yekkiralabeb8d132006-08-04 23:12:42 -0700605 security_sk_classify_flow(sk, &fl);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800606
607 if (ip6_dst_lookup(sk, &dst, &fl))
608 goto out;
609
610 if (final_p)
611 ipv6_addr_copy(&fl.fl6_dst, final_p);
612
613 if ((xfrm_lookup(&dst, &fl, sk, 0)) < 0)
614 goto out;
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800615 }
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800616
617 newsk = dccp_create_openreq_child(sk, req, skb);
618 if (newsk == NULL)
619 goto out;
620
621 /*
622 * No need to charge this sock to the relevant IPv6 refcnt debug socks
623 * count here, dccp_create_openreq_child now does this for us, see the
624 * comment in that function for the gory details. -acme
625 */
626
YOSHIFUJI Hideaki8e1ef0a2006-08-29 17:15:09 -0700627 __ip6_dst_store(newsk, dst, NULL, NULL);
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800628 newsk->sk_route_caps = dst->dev->features & ~(NETIF_F_IP_CSUM |
629 NETIF_F_TSO);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800630 newdp6 = (struct dccp6_sock *)newsk;
631 newinet = inet_sk(newsk);
632 newinet->pinet6 = &newdp6->inet6;
633 newdp = dccp_sk(newsk);
634 newnp = inet6_sk(newsk);
635
636 memcpy(newnp, np, sizeof(struct ipv6_pinfo));
637
638 ipv6_addr_copy(&newnp->daddr, &ireq6->rmt_addr);
639 ipv6_addr_copy(&newnp->saddr, &ireq6->loc_addr);
640 ipv6_addr_copy(&newnp->rcv_saddr, &ireq6->loc_addr);
641 newsk->sk_bound_dev_if = ireq6->iif;
642
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800643 /* Now IPv6 options...
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800644
645 First: no IPv4 options.
646 */
647 newinet->opt = NULL;
648
649 /* Clone RX bits */
650 newnp->rxopt.all = np->rxopt.all;
651
652 /* Clone pktoptions received with SYN */
653 newnp->pktoptions = NULL;
654 if (ireq6->pktopts != NULL) {
655 newnp->pktoptions = skb_clone(ireq6->pktopts, GFP_ATOMIC);
656 kfree_skb(ireq6->pktopts);
657 ireq6->pktopts = NULL;
658 if (newnp->pktoptions)
659 skb_set_owner_r(newnp->pktoptions, newsk);
660 }
661 newnp->opt = NULL;
662 newnp->mcast_oif = inet6_iif(skb);
663 newnp->mcast_hops = skb->nh.ipv6h->hop_limit;
664
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800665 /*
666 * Clone native IPv6 options from listening socket (if any)
667 *
668 * Yes, keeping reference count would be much more clever, but we make
669 * one more one thing there: reattach optmem to newsk.
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800670 */
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800671 if (opt != NULL) {
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800672 newnp->opt = ipv6_dup_options(newsk, opt);
673 if (opt != np->opt)
674 sock_kfree_s(sk, opt, opt->tot_len);
675 }
676
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -0800677 inet_csk(newsk)->icsk_ext_hdr_len = 0;
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800678 if (newnp->opt != NULL)
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -0800679 inet_csk(newsk)->icsk_ext_hdr_len = (newnp->opt->opt_nflen +
680 newnp->opt->opt_flen);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800681
682 dccp_sync_mss(newsk, dst_mtu(dst));
683
684 newinet->daddr = newinet->saddr = newinet->rcv_saddr = LOOPBACK4_IPV6;
685
686 __inet6_hash(&dccp_hashinfo, newsk);
687 inet_inherit_port(&dccp_hashinfo, sk, newsk);
688
689 return newsk;
690
691out_overflow:
692 NET_INC_STATS_BH(LINUX_MIB_LISTENOVERFLOWS);
693out:
694 NET_INC_STATS_BH(LINUX_MIB_LISTENDROPS);
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800695 if (opt != NULL && opt != np->opt)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800696 sock_kfree_s(sk, opt, opt->tot_len);
697 dst_release(dst);
698 return NULL;
699}
700
701/* The socket must have it's spinlock held when we get
702 * here.
703 *
704 * We have a potential double-lock case here, so even when
705 * doing backlog processing we use the BH locking scheme.
706 * This is because we cannot sleep with the original spinlock
707 * held.
708 */
709static int dccp_v6_do_rcv(struct sock *sk, struct sk_buff *skb)
710{
711 struct ipv6_pinfo *np = inet6_sk(sk);
712 struct sk_buff *opt_skb = NULL;
713
714 /* Imagine: socket is IPv6. IPv4 packet arrives,
715 goes to IPv4 receive handler and backlogged.
716 From backlog it always goes here. Kerboom...
717 Fortunately, dccp_rcv_established and rcv_established
718 handle them correctly, but it is not case with
719 dccp_v6_hnd_req and dccp_v6_ctl_send_reset(). --ANK
720 */
721
722 if (skb->protocol == htons(ETH_P_IP))
723 return dccp_v4_do_rcv(sk, skb);
724
Dmitry Mishinfda9ef52006-08-31 15:28:39 -0700725 if (sk_filter(sk, skb))
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800726 goto discard;
727
728 /*
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800729 * socket locking is here for SMP purposes as backlog rcv is currently
730 * called with bh processing disabled.
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800731 */
732
733 /* Do Stevens' IPV6_PKTOPTIONS.
734
735 Yes, guys, it is the only place in our code, where we
736 may make it not affecting IPv4.
737 The rest of code is protocol independent,
738 and I do not like idea to uglify IPv4.
739
740 Actually, all the idea behind IPV6_PKTOPTIONS
741 looks not very well thought. For now we latch
742 options, received in the last packet, enqueued
743 by tcp. Feel free to propose better solution.
744 --ANK (980728)
745 */
746 if (np->rxopt.all)
Gerrit Renker89e7e572006-11-10 11:13:33 -0200747 /*
748 * FIXME: Add handling of IPV6_PKTOPTIONS skb. See the comments below
749 * (wrt ipv6_pktopions) and net/ipv6/tcp_ipv6.c for an example.
750 */
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800751 opt_skb = skb_clone(skb, GFP_ATOMIC);
752
753 if (sk->sk_state == DCCP_OPEN) { /* Fast path */
754 if (dccp_rcv_established(sk, skb, dccp_hdr(skb), skb->len))
755 goto reset;
David S. Millerfd169f12006-10-20 19:44:17 -0700756 if (opt_skb) {
Gerrit Renker89e7e572006-11-10 11:13:33 -0200757 /* XXX This is where we would goto ipv6_pktoptions. */
David S. Millerfd169f12006-10-20 19:44:17 -0700758 __kfree_skb(opt_skb);
759 }
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800760 return 0;
761 }
762
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800763 if (sk->sk_state == DCCP_LISTEN) {
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800764 struct sock *nsk = dccp_v6_hnd_req(sk, skb);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800765
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800766 if (nsk == NULL)
767 goto discard;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800768 /*
769 * Queue it on the new socket if the new socket is active,
770 * otherwise we just shortcircuit this and continue with
771 * the new socket..
772 */
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800773 if (nsk != sk) {
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800774 if (dccp_child_process(sk, nsk, skb))
775 goto reset;
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800776 if (opt_skb != NULL)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800777 __kfree_skb(opt_skb);
778 return 0;
779 }
780 }
781
782 if (dccp_rcv_state_process(sk, skb, dccp_hdr(skb), skb->len))
783 goto reset;
David S. Millerfd169f12006-10-20 19:44:17 -0700784 if (opt_skb) {
Gerrit Renker89e7e572006-11-10 11:13:33 -0200785 /* XXX This is where we would goto ipv6_pktoptions. */
David S. Millerfd169f12006-10-20 19:44:17 -0700786 __kfree_skb(opt_skb);
787 }
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800788 return 0;
789
790reset:
791 dccp_v6_ctl_send_reset(skb);
792discard:
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800793 if (opt_skb != NULL)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800794 __kfree_skb(opt_skb);
795 kfree_skb(skb);
796 return 0;
797}
798
Patrick McHardy951dbc82006-01-06 23:02:34 -0800799static int dccp_v6_rcv(struct sk_buff **pskb)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800800{
801 const struct dccp_hdr *dh;
802 struct sk_buff *skb = *pskb;
803 struct sock *sk;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800804
805 /* Step 1: Check header basics: */
806
807 if (dccp_invalid_packet(skb))
808 goto discard_it;
809
810 dh = dccp_hdr(skb);
811
812 DCCP_SKB_CB(skb)->dccpd_seq = dccp_hdr_seq(skb);
813 DCCP_SKB_CB(skb)->dccpd_type = dh->dccph_type;
814
815 if (dccp_packet_without_ack(skb))
816 DCCP_SKB_CB(skb)->dccpd_ack_seq = DCCP_PKT_WITHOUT_ACK_SEQ;
817 else
818 DCCP_SKB_CB(skb)->dccpd_ack_seq = dccp_hdr_ack_seq(skb);
819
820 /* Step 2:
821 * Look up flow ID in table and get corresponding socket */
822 sk = __inet6_lookup(&dccp_hashinfo, &skb->nh.ipv6h->saddr,
823 dh->dccph_sport,
824 &skb->nh.ipv6h->daddr, ntohs(dh->dccph_dport),
825 inet6_iif(skb));
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800826 /*
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800827 * Step 2:
828 * If no socket ...
829 * Generate Reset(No Connection) unless P.type == Reset
830 * Drop packet and return
831 */
Gerrit Renkerd23c7102006-11-10 11:46:34 -0200832 if (sk == NULL) {
833 dccp_pr_debug("failed to look up flow ID in table and "
834 "get corresponding socket\n");
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800835 goto no_dccp_socket;
Gerrit Renkerd23c7102006-11-10 11:46:34 -0200836 }
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800837
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800838 /*
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800839 * Step 2:
840 * ... or S.state == TIMEWAIT,
841 * Generate Reset(No Connection) unless P.type == Reset
842 * Drop packet and return
843 */
Gerrit Renkerd23c7102006-11-10 11:46:34 -0200844 if (sk->sk_state == DCCP_TIME_WAIT) {
845 dccp_pr_debug("sk->sk_state == DCCP_TIME_WAIT: do_time_wait\n");
846 inet_twsk_put(inet_twsk(sk));
847 goto no_dccp_socket;
848 }
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800849
850 if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb))
851 goto discard_and_relse;
852
Arnaldo Carvalho de Melo25995ff2005-12-27 02:42:22 -0200853 return sk_receive_skb(sk, skb) ? -1 : 0;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800854
855no_dccp_socket:
856 if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb))
857 goto discard_it;
858 /*
859 * Step 2:
860 * Generate Reset(No Connection) unless P.type == Reset
861 * Drop packet and return
862 */
863 if (dh->dccph_type != DCCP_PKT_RESET) {
864 DCCP_SKB_CB(skb)->dccpd_reset_code =
865 DCCP_RESET_CODE_NO_CONNECTION;
866 dccp_v6_ctl_send_reset(skb);
867 }
Gerrit Renkerd23c7102006-11-10 11:46:34 -0200868
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800869discard_it:
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800870 kfree_skb(skb);
871 return 0;
872
873discard_and_relse:
874 sock_put(sk);
875 goto discard_it;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800876}
877
Gerrit Renker73c9e022006-11-10 13:01:31 -0200878static int dccp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
879 int addr_len)
880{
881 struct sockaddr_in6 *usin = (struct sockaddr_in6 *)uaddr;
882 struct inet_connection_sock *icsk = inet_csk(sk);
883 struct inet_sock *inet = inet_sk(sk);
884 struct ipv6_pinfo *np = inet6_sk(sk);
885 struct dccp_sock *dp = dccp_sk(sk);
886 struct in6_addr *saddr = NULL, *final_p = NULL, final;
887 struct flowi fl;
888 struct dst_entry *dst;
889 int addr_type;
890 int err;
891
892 dp->dccps_role = DCCP_ROLE_CLIENT;
893
894 if (addr_len < SIN6_LEN_RFC2133)
895 return -EINVAL;
896
897 if (usin->sin6_family != AF_INET6)
898 return -EAFNOSUPPORT;
899
900 memset(&fl, 0, sizeof(fl));
901
902 if (np->sndflow) {
903 fl.fl6_flowlabel = usin->sin6_flowinfo & IPV6_FLOWINFO_MASK;
904 IP6_ECN_flow_init(fl.fl6_flowlabel);
905 if (fl.fl6_flowlabel & IPV6_FLOWLABEL_MASK) {
906 struct ip6_flowlabel *flowlabel;
907 flowlabel = fl6_sock_lookup(sk, fl.fl6_flowlabel);
908 if (flowlabel == NULL)
909 return -EINVAL;
910 ipv6_addr_copy(&usin->sin6_addr, &flowlabel->dst);
911 fl6_sock_release(flowlabel);
912 }
913 }
914 /*
915 * connect() to INADDR_ANY means loopback (BSD'ism).
916 */
917 if (ipv6_addr_any(&usin->sin6_addr))
918 usin->sin6_addr.s6_addr[15] = 1;
919
920 addr_type = ipv6_addr_type(&usin->sin6_addr);
921
922 if (addr_type & IPV6_ADDR_MULTICAST)
923 return -ENETUNREACH;
924
925 if (addr_type & IPV6_ADDR_LINKLOCAL) {
926 if (addr_len >= sizeof(struct sockaddr_in6) &&
927 usin->sin6_scope_id) {
928 /* If interface is set while binding, indices
929 * must coincide.
930 */
931 if (sk->sk_bound_dev_if &&
932 sk->sk_bound_dev_if != usin->sin6_scope_id)
933 return -EINVAL;
934
935 sk->sk_bound_dev_if = usin->sin6_scope_id;
936 }
937
938 /* Connect to link-local address requires an interface */
939 if (!sk->sk_bound_dev_if)
940 return -EINVAL;
941 }
942
943 ipv6_addr_copy(&np->daddr, &usin->sin6_addr);
944 np->flow_label = fl.fl6_flowlabel;
945
946 /*
947 * DCCP over IPv4
948 */
949 if (addr_type == IPV6_ADDR_MAPPED) {
950 u32 exthdrlen = icsk->icsk_ext_hdr_len;
951 struct sockaddr_in sin;
952
953 SOCK_DEBUG(sk, "connect: ipv4 mapped\n");
954
955 if (__ipv6_only_sock(sk))
956 return -ENETUNREACH;
957
958 sin.sin_family = AF_INET;
959 sin.sin_port = usin->sin6_port;
960 sin.sin_addr.s_addr = usin->sin6_addr.s6_addr32[3];
961
962 icsk->icsk_af_ops = &dccp_ipv6_mapped;
963 sk->sk_backlog_rcv = dccp_v4_do_rcv;
964
965 err = dccp_v4_connect(sk, (struct sockaddr *)&sin, sizeof(sin));
966 if (err) {
967 icsk->icsk_ext_hdr_len = exthdrlen;
968 icsk->icsk_af_ops = &dccp_ipv6_af_ops;
969 sk->sk_backlog_rcv = dccp_v6_do_rcv;
970 goto failure;
971 } else {
972 ipv6_addr_set(&np->saddr, 0, 0, htonl(0x0000FFFF),
973 inet->saddr);
974 ipv6_addr_set(&np->rcv_saddr, 0, 0, htonl(0x0000FFFF),
975 inet->rcv_saddr);
976 }
977
978 return err;
979 }
980
981 if (!ipv6_addr_any(&np->rcv_saddr))
982 saddr = &np->rcv_saddr;
983
984 fl.proto = IPPROTO_DCCP;
985 ipv6_addr_copy(&fl.fl6_dst, &np->daddr);
986 ipv6_addr_copy(&fl.fl6_src, saddr ? saddr : &np->saddr);
987 fl.oif = sk->sk_bound_dev_if;
988 fl.fl_ip_dport = usin->sin6_port;
989 fl.fl_ip_sport = inet->sport;
990 security_sk_classify_flow(sk, &fl);
991
992 if (np->opt != NULL && np->opt->srcrt != NULL) {
993 const struct rt0_hdr *rt0 = (struct rt0_hdr *)np->opt->srcrt;
994
995 ipv6_addr_copy(&final, &fl.fl6_dst);
996 ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
997 final_p = &final;
998 }
999
1000 err = ip6_dst_lookup(sk, &dst, &fl);
1001 if (err)
1002 goto failure;
1003
1004 if (final_p)
1005 ipv6_addr_copy(&fl.fl6_dst, final_p);
1006
1007 err = xfrm_lookup(&dst, &fl, sk, 0);
1008 if (err < 0)
1009 goto failure;
1010
1011 if (saddr == NULL) {
1012 saddr = &fl.fl6_src;
1013 ipv6_addr_copy(&np->rcv_saddr, saddr);
1014 }
1015
1016 /* set the source address */
1017 ipv6_addr_copy(&np->saddr, saddr);
1018 inet->rcv_saddr = LOOPBACK4_IPV6;
1019
1020 __ip6_dst_store(sk, dst, NULL, NULL);
1021
1022 icsk->icsk_ext_hdr_len = 0;
1023 if (np->opt != NULL)
1024 icsk->icsk_ext_hdr_len = (np->opt->opt_flen +
1025 np->opt->opt_nflen);
1026
1027 inet->dport = usin->sin6_port;
1028
1029 dccp_set_state(sk, DCCP_REQUESTING);
1030 err = inet6_hash_connect(&dccp_death_row, sk);
1031 if (err)
1032 goto late_failure;
1033 /* FIXME */
1034#if 0
1035 dp->dccps_gar = secure_dccp_v6_sequence_number(np->saddr.s6_addr32,
1036 np->daddr.s6_addr32,
1037 inet->sport,
1038 inet->dport);
1039#endif
1040 err = dccp_connect(sk);
1041 if (err)
1042 goto late_failure;
1043
1044 return 0;
1045
1046late_failure:
1047 dccp_set_state(sk, DCCP_CLOSED);
1048 __sk_dst_reset(sk);
1049failure:
1050 inet->dport = 0;
1051 sk->sk_route_caps = 0;
1052 return err;
1053}
1054
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001055static struct inet_connection_sock_af_ops dccp_ipv6_af_ops = {
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001056 .queue_xmit = inet6_csk_xmit,
1057 .send_check = dccp_v6_send_check,
1058 .rebuild_header = inet6_sk_rebuild_header,
1059 .conn_request = dccp_v6_conn_request,
1060 .syn_recv_sock = dccp_v6_request_recv_sock,
1061 .net_header_len = sizeof(struct ipv6hdr),
1062 .setsockopt = ipv6_setsockopt,
1063 .getsockopt = ipv6_getsockopt,
1064 .addr2sockaddr = inet6_csk_addr2sockaddr,
1065 .sockaddr_len = sizeof(struct sockaddr_in6),
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001066#ifdef CONFIG_COMPAT
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001067 .compat_setsockopt = compat_ipv6_setsockopt,
1068 .compat_getsockopt = compat_ipv6_getsockopt,
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001069#endif
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001070};
1071
1072/*
1073 * DCCP over IPv4 via INET6 API
1074 */
1075static struct inet_connection_sock_af_ops dccp_ipv6_mapped = {
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001076 .queue_xmit = ip_queue_xmit,
1077 .send_check = dccp_v4_send_check,
1078 .rebuild_header = inet_sk_rebuild_header,
1079 .conn_request = dccp_v6_conn_request,
1080 .syn_recv_sock = dccp_v6_request_recv_sock,
1081 .net_header_len = sizeof(struct iphdr),
1082 .setsockopt = ipv6_setsockopt,
1083 .getsockopt = ipv6_getsockopt,
1084 .addr2sockaddr = inet6_csk_addr2sockaddr,
1085 .sockaddr_len = sizeof(struct sockaddr_in6),
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001086#ifdef CONFIG_COMPAT
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001087 .compat_setsockopt = compat_ipv6_setsockopt,
1088 .compat_getsockopt = compat_ipv6_getsockopt,
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001089#endif
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001090};
1091
1092/* NOTE: A lot of things set to zero explicitly by call to
1093 * sk_alloc() so need not be done here.
1094 */
1095static int dccp_v6_init_sock(struct sock *sk)
1096{
Arnaldo Carvalho de Melo72478872006-03-20 22:00:37 -08001097 static __u8 dccp_v6_ctl_sock_initialized;
1098 int err = dccp_init_sock(sk, dccp_v6_ctl_sock_initialized);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001099
Arnaldo Carvalho de Melo72478872006-03-20 22:00:37 -08001100 if (err == 0) {
1101 if (unlikely(!dccp_v6_ctl_sock_initialized))
1102 dccp_v6_ctl_sock_initialized = 1;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001103 inet_csk(sk)->icsk_af_ops = &dccp_ipv6_af_ops;
Arnaldo Carvalho de Melo72478872006-03-20 22:00:37 -08001104 }
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001105
1106 return err;
1107}
1108
1109static int dccp_v6_destroy_sock(struct sock *sk)
1110{
Arnaldo Carvalho de Melo3e0fadc2006-03-20 21:23:15 -08001111 dccp_destroy_sock(sk);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001112 return inet6_destroy_sock(sk);
1113}
1114
Gerrit Renker73c9e022006-11-10 13:01:31 -02001115static struct timewait_sock_ops dccp6_timewait_sock_ops = {
1116 .twsk_obj_size = sizeof(struct dccp6_timewait_sock),
1117};
1118
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001119static struct proto dccp_v6_prot = {
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001120 .name = "DCCPv6",
1121 .owner = THIS_MODULE,
1122 .close = dccp_close,
1123 .connect = dccp_v6_connect,
1124 .disconnect = dccp_disconnect,
1125 .ioctl = dccp_ioctl,
1126 .init = dccp_v6_init_sock,
1127 .setsockopt = dccp_setsockopt,
1128 .getsockopt = dccp_getsockopt,
1129 .sendmsg = dccp_sendmsg,
1130 .recvmsg = dccp_recvmsg,
1131 .backlog_rcv = dccp_v6_do_rcv,
1132 .hash = dccp_v6_hash,
1133 .unhash = dccp_unhash,
1134 .accept = inet_csk_accept,
1135 .get_port = dccp_v6_get_port,
1136 .shutdown = dccp_shutdown,
1137 .destroy = dccp_v6_destroy_sock,
1138 .orphan_count = &dccp_orphan_count,
1139 .max_header = MAX_DCCP_HEADER,
1140 .obj_size = sizeof(struct dccp6_sock),
1141 .rsk_prot = &dccp6_request_sock_ops,
1142 .twsk_prot = &dccp6_timewait_sock_ops,
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001143#ifdef CONFIG_COMPAT
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001144 .compat_setsockopt = compat_dccp_setsockopt,
1145 .compat_getsockopt = compat_dccp_getsockopt,
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001146#endif
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001147};
1148
1149static struct inet6_protocol dccp_v6_protocol = {
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -08001150 .handler = dccp_v6_rcv,
1151 .err_handler = dccp_v6_err,
1152 .flags = INET6_PROTO_NOPOLICY | INET6_PROTO_FINAL,
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001153};
1154
1155static struct proto_ops inet6_dccp_ops = {
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001156 .family = PF_INET6,
1157 .owner = THIS_MODULE,
1158 .release = inet6_release,
1159 .bind = inet6_bind,
1160 .connect = inet_stream_connect,
1161 .socketpair = sock_no_socketpair,
1162 .accept = inet_accept,
1163 .getname = inet6_getname,
1164 .poll = dccp_poll,
1165 .ioctl = inet6_ioctl,
1166 .listen = inet_dccp_listen,
1167 .shutdown = inet_shutdown,
1168 .setsockopt = sock_common_setsockopt,
1169 .getsockopt = sock_common_getsockopt,
1170 .sendmsg = inet_sendmsg,
1171 .recvmsg = sock_common_recvmsg,
1172 .mmap = sock_no_mmap,
1173 .sendpage = sock_no_sendpage,
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001174#ifdef CONFIG_COMPAT
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001175 .compat_setsockopt = compat_sock_common_setsockopt,
1176 .compat_getsockopt = compat_sock_common_getsockopt,
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001177#endif
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001178};
1179
1180static struct inet_protosw dccp_v6_protosw = {
1181 .type = SOCK_DCCP,
1182 .protocol = IPPROTO_DCCP,
1183 .prot = &dccp_v6_prot,
1184 .ops = &inet6_dccp_ops,
1185 .capability = -1,
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -08001186 .flags = INET_PROTOSW_ICSK,
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001187};
1188
1189static int __init dccp_v6_init(void)
1190{
1191 int err = proto_register(&dccp_v6_prot, 1);
1192
1193 if (err != 0)
1194 goto out;
1195
1196 err = inet6_add_protocol(&dccp_v6_protocol, IPPROTO_DCCP);
1197 if (err != 0)
1198 goto out_unregister_proto;
1199
1200 inet6_register_protosw(&dccp_v6_protosw);
Arnaldo Carvalho de Melo72478872006-03-20 22:00:37 -08001201
Arnaldo Carvalho de Meloc4d93902006-03-20 22:01:03 -08001202 err = inet_csk_ctl_sock_create(&dccp_v6_ctl_socket, PF_INET6,
1203 SOCK_DCCP, IPPROTO_DCCP);
1204 if (err != 0)
Arnaldo Carvalho de Melo72478872006-03-20 22:00:37 -08001205 goto out_unregister_protosw;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001206out:
1207 return err;
Arnaldo Carvalho de Melo72478872006-03-20 22:00:37 -08001208out_unregister_protosw:
1209 inet6_del_protocol(&dccp_v6_protocol, IPPROTO_DCCP);
1210 inet6_unregister_protosw(&dccp_v6_protosw);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001211out_unregister_proto:
1212 proto_unregister(&dccp_v6_prot);
1213 goto out;
1214}
1215
1216static void __exit dccp_v6_exit(void)
1217{
1218 inet6_del_protocol(&dccp_v6_protocol, IPPROTO_DCCP);
1219 inet6_unregister_protosw(&dccp_v6_protosw);
1220 proto_unregister(&dccp_v6_prot);
1221}
1222
1223module_init(dccp_v6_init);
1224module_exit(dccp_v6_exit);
1225
1226/*
1227 * __stringify doesn't likes enums, so use SOCK_DCCP (6) and IPPROTO_DCCP (33)
1228 * values directly, Also cover the case where the protocol is not specified,
1229 * i.e. net-pf-PF_INET6-proto-0-type-SOCK_DCCP
1230 */
1231MODULE_ALIAS("net-pf-" __stringify(PF_INET6) "-proto-33-type-6");
1232MODULE_ALIAS("net-pf-" __stringify(PF_INET6) "-proto-0-type-6");
1233MODULE_LICENSE("GPL");
1234MODULE_AUTHOR("Arnaldo Carvalho de Melo <acme@mandriva.com>");
1235MODULE_DESCRIPTION("DCCPv6 - Datagram Congestion Controlled Protocol");