blob: 201801e1532d8d33c7705f07952f70c0f880f979 [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 *
Gerrit Renkerd83ca5a2006-11-10 16:29:14 -0200490 * Set S.ISR, S.GSR, S.SWL, S.SWH from packet or Init Cookie
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800491 *
Gerrit Renkerd83ca5a2006-11-10 16:29:14 -0200492 * In fact we defer setting S.GSR, S.SWL, S.SWH to
493 * dccp_create_openreq_child.
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800494 */
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
Gerrit Renkerd83ca5a2006-11-10 16:29:14 -0200763 /*
764 * Step 3: Process LISTEN state
765 * If S.state == LISTEN,
766 * If P.type == Request or P contains a valid Init Cookie option,
767 * (* Must scan the packet's options to check for Init
768 * Cookies. Only Init Cookies are processed here,
769 * however; other options are processed in Step 8. This
770 * scan need only be performed if the endpoint uses Init
771 * Cookies *)
772 * (* Generate a new socket and switch to that socket *)
773 * Set S := new socket for this port pair
774 * S.state = RESPOND
775 * Choose S.ISS (initial seqno) or set from Init Cookies
776 * Initialize S.GAR := S.ISS
777 * Set S.ISR, S.GSR, S.SWL, S.SWH from packet or Init Cookies
778 * Continue with S.state == RESPOND
779 * (* A Response packet will be generated in Step 11 *)
780 * Otherwise,
781 * Generate Reset(No Connection) unless P.type == Reset
782 * Drop packet and return
783 *
784 * NOTE: the check for the packet types is done in
785 * dccp_rcv_state_process
786 */
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800787 if (sk->sk_state == DCCP_LISTEN) {
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800788 struct sock *nsk = dccp_v6_hnd_req(sk, skb);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800789
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800790 if (nsk == NULL)
791 goto discard;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800792 /*
793 * Queue it on the new socket if the new socket is active,
794 * otherwise we just shortcircuit this and continue with
795 * the new socket..
796 */
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800797 if (nsk != sk) {
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800798 if (dccp_child_process(sk, nsk, skb))
799 goto reset;
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800800 if (opt_skb != NULL)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800801 __kfree_skb(opt_skb);
802 return 0;
803 }
804 }
805
806 if (dccp_rcv_state_process(sk, skb, dccp_hdr(skb), skb->len))
807 goto reset;
David S. Millerfd169f12006-10-20 19:44:17 -0700808 if (opt_skb) {
Gerrit Renker89e7e572006-11-10 11:13:33 -0200809 /* XXX This is where we would goto ipv6_pktoptions. */
David S. Millerfd169f12006-10-20 19:44:17 -0700810 __kfree_skb(opt_skb);
811 }
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800812 return 0;
813
814reset:
815 dccp_v6_ctl_send_reset(skb);
816discard:
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800817 if (opt_skb != NULL)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800818 __kfree_skb(opt_skb);
819 kfree_skb(skb);
820 return 0;
821}
822
Patrick McHardy951dbc82006-01-06 23:02:34 -0800823static int dccp_v6_rcv(struct sk_buff **pskb)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800824{
825 const struct dccp_hdr *dh;
826 struct sk_buff *skb = *pskb;
827 struct sock *sk;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800828
829 /* Step 1: Check header basics: */
830
831 if (dccp_invalid_packet(skb))
832 goto discard_it;
833
834 dh = dccp_hdr(skb);
835
836 DCCP_SKB_CB(skb)->dccpd_seq = dccp_hdr_seq(skb);
837 DCCP_SKB_CB(skb)->dccpd_type = dh->dccph_type;
838
839 if (dccp_packet_without_ack(skb))
840 DCCP_SKB_CB(skb)->dccpd_ack_seq = DCCP_PKT_WITHOUT_ACK_SEQ;
841 else
842 DCCP_SKB_CB(skb)->dccpd_ack_seq = dccp_hdr_ack_seq(skb);
843
844 /* Step 2:
845 * Look up flow ID in table and get corresponding socket */
846 sk = __inet6_lookup(&dccp_hashinfo, &skb->nh.ipv6h->saddr,
847 dh->dccph_sport,
848 &skb->nh.ipv6h->daddr, ntohs(dh->dccph_dport),
849 inet6_iif(skb));
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800850 /*
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800851 * Step 2:
852 * If no socket ...
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800853 */
Gerrit Renkerd23c7102006-11-10 11:46:34 -0200854 if (sk == NULL) {
855 dccp_pr_debug("failed to look up flow ID in table and "
856 "get corresponding socket\n");
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800857 goto no_dccp_socket;
Gerrit Renkerd23c7102006-11-10 11:46:34 -0200858 }
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800859
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800860 /*
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800861 * Step 2:
862 * ... or S.state == TIMEWAIT,
863 * Generate Reset(No Connection) unless P.type == Reset
864 * Drop packet and return
865 */
Gerrit Renkerd23c7102006-11-10 11:46:34 -0200866 if (sk->sk_state == DCCP_TIME_WAIT) {
867 dccp_pr_debug("sk->sk_state == DCCP_TIME_WAIT: do_time_wait\n");
868 inet_twsk_put(inet_twsk(sk));
869 goto no_dccp_socket;
870 }
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800871
872 if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb))
873 goto discard_and_relse;
874
Arnaldo Carvalho de Melo25995ff2005-12-27 02:42:22 -0200875 return sk_receive_skb(sk, skb) ? -1 : 0;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800876
877no_dccp_socket:
878 if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb))
879 goto discard_it;
880 /*
881 * Step 2:
Gerrit Renkerd83ca5a2006-11-10 16:29:14 -0200882 * If no socket ...
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800883 * Generate Reset(No Connection) unless P.type == Reset
884 * Drop packet and return
885 */
886 if (dh->dccph_type != DCCP_PKT_RESET) {
887 DCCP_SKB_CB(skb)->dccpd_reset_code =
888 DCCP_RESET_CODE_NO_CONNECTION;
889 dccp_v6_ctl_send_reset(skb);
890 }
Gerrit Renkerd23c7102006-11-10 11:46:34 -0200891
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800892discard_it:
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800893 kfree_skb(skb);
894 return 0;
895
896discard_and_relse:
897 sock_put(sk);
898 goto discard_it;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800899}
900
Gerrit Renker73c9e022006-11-10 13:01:31 -0200901static int dccp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
902 int addr_len)
903{
904 struct sockaddr_in6 *usin = (struct sockaddr_in6 *)uaddr;
905 struct inet_connection_sock *icsk = inet_csk(sk);
906 struct inet_sock *inet = inet_sk(sk);
907 struct ipv6_pinfo *np = inet6_sk(sk);
908 struct dccp_sock *dp = dccp_sk(sk);
909 struct in6_addr *saddr = NULL, *final_p = NULL, final;
910 struct flowi fl;
911 struct dst_entry *dst;
912 int addr_type;
913 int err;
914
915 dp->dccps_role = DCCP_ROLE_CLIENT;
916
917 if (addr_len < SIN6_LEN_RFC2133)
918 return -EINVAL;
919
920 if (usin->sin6_family != AF_INET6)
921 return -EAFNOSUPPORT;
922
923 memset(&fl, 0, sizeof(fl));
924
925 if (np->sndflow) {
926 fl.fl6_flowlabel = usin->sin6_flowinfo & IPV6_FLOWINFO_MASK;
927 IP6_ECN_flow_init(fl.fl6_flowlabel);
928 if (fl.fl6_flowlabel & IPV6_FLOWLABEL_MASK) {
929 struct ip6_flowlabel *flowlabel;
930 flowlabel = fl6_sock_lookup(sk, fl.fl6_flowlabel);
931 if (flowlabel == NULL)
932 return -EINVAL;
933 ipv6_addr_copy(&usin->sin6_addr, &flowlabel->dst);
934 fl6_sock_release(flowlabel);
935 }
936 }
937 /*
938 * connect() to INADDR_ANY means loopback (BSD'ism).
939 */
940 if (ipv6_addr_any(&usin->sin6_addr))
941 usin->sin6_addr.s6_addr[15] = 1;
942
943 addr_type = ipv6_addr_type(&usin->sin6_addr);
944
945 if (addr_type & IPV6_ADDR_MULTICAST)
946 return -ENETUNREACH;
947
948 if (addr_type & IPV6_ADDR_LINKLOCAL) {
949 if (addr_len >= sizeof(struct sockaddr_in6) &&
950 usin->sin6_scope_id) {
951 /* If interface is set while binding, indices
952 * must coincide.
953 */
954 if (sk->sk_bound_dev_if &&
955 sk->sk_bound_dev_if != usin->sin6_scope_id)
956 return -EINVAL;
957
958 sk->sk_bound_dev_if = usin->sin6_scope_id;
959 }
960
961 /* Connect to link-local address requires an interface */
962 if (!sk->sk_bound_dev_if)
963 return -EINVAL;
964 }
965
966 ipv6_addr_copy(&np->daddr, &usin->sin6_addr);
967 np->flow_label = fl.fl6_flowlabel;
968
969 /*
970 * DCCP over IPv4
971 */
972 if (addr_type == IPV6_ADDR_MAPPED) {
973 u32 exthdrlen = icsk->icsk_ext_hdr_len;
974 struct sockaddr_in sin;
975
976 SOCK_DEBUG(sk, "connect: ipv4 mapped\n");
977
978 if (__ipv6_only_sock(sk))
979 return -ENETUNREACH;
980
981 sin.sin_family = AF_INET;
982 sin.sin_port = usin->sin6_port;
983 sin.sin_addr.s_addr = usin->sin6_addr.s6_addr32[3];
984
985 icsk->icsk_af_ops = &dccp_ipv6_mapped;
986 sk->sk_backlog_rcv = dccp_v4_do_rcv;
987
988 err = dccp_v4_connect(sk, (struct sockaddr *)&sin, sizeof(sin));
989 if (err) {
990 icsk->icsk_ext_hdr_len = exthdrlen;
991 icsk->icsk_af_ops = &dccp_ipv6_af_ops;
992 sk->sk_backlog_rcv = dccp_v6_do_rcv;
993 goto failure;
994 } else {
995 ipv6_addr_set(&np->saddr, 0, 0, htonl(0x0000FFFF),
996 inet->saddr);
997 ipv6_addr_set(&np->rcv_saddr, 0, 0, htonl(0x0000FFFF),
998 inet->rcv_saddr);
999 }
1000
1001 return err;
1002 }
1003
1004 if (!ipv6_addr_any(&np->rcv_saddr))
1005 saddr = &np->rcv_saddr;
1006
1007 fl.proto = IPPROTO_DCCP;
1008 ipv6_addr_copy(&fl.fl6_dst, &np->daddr);
1009 ipv6_addr_copy(&fl.fl6_src, saddr ? saddr : &np->saddr);
1010 fl.oif = sk->sk_bound_dev_if;
1011 fl.fl_ip_dport = usin->sin6_port;
1012 fl.fl_ip_sport = inet->sport;
1013 security_sk_classify_flow(sk, &fl);
1014
1015 if (np->opt != NULL && np->opt->srcrt != NULL) {
1016 const struct rt0_hdr *rt0 = (struct rt0_hdr *)np->opt->srcrt;
1017
1018 ipv6_addr_copy(&final, &fl.fl6_dst);
1019 ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
1020 final_p = &final;
1021 }
1022
1023 err = ip6_dst_lookup(sk, &dst, &fl);
1024 if (err)
1025 goto failure;
1026
1027 if (final_p)
1028 ipv6_addr_copy(&fl.fl6_dst, final_p);
1029
1030 err = xfrm_lookup(&dst, &fl, sk, 0);
1031 if (err < 0)
1032 goto failure;
1033
1034 if (saddr == NULL) {
1035 saddr = &fl.fl6_src;
1036 ipv6_addr_copy(&np->rcv_saddr, saddr);
1037 }
1038
1039 /* set the source address */
1040 ipv6_addr_copy(&np->saddr, saddr);
1041 inet->rcv_saddr = LOOPBACK4_IPV6;
1042
1043 __ip6_dst_store(sk, dst, NULL, NULL);
1044
1045 icsk->icsk_ext_hdr_len = 0;
1046 if (np->opt != NULL)
1047 icsk->icsk_ext_hdr_len = (np->opt->opt_flen +
1048 np->opt->opt_nflen);
1049
1050 inet->dport = usin->sin6_port;
1051
1052 dccp_set_state(sk, DCCP_REQUESTING);
1053 err = inet6_hash_connect(&dccp_death_row, sk);
1054 if (err)
1055 goto late_failure;
1056 /* FIXME */
1057#if 0
1058 dp->dccps_gar = secure_dccp_v6_sequence_number(np->saddr.s6_addr32,
1059 np->daddr.s6_addr32,
1060 inet->sport,
1061 inet->dport);
1062#endif
1063 err = dccp_connect(sk);
1064 if (err)
1065 goto late_failure;
1066
1067 return 0;
1068
1069late_failure:
1070 dccp_set_state(sk, DCCP_CLOSED);
1071 __sk_dst_reset(sk);
1072failure:
1073 inet->dport = 0;
1074 sk->sk_route_caps = 0;
1075 return err;
1076}
1077
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001078static struct inet_connection_sock_af_ops dccp_ipv6_af_ops = {
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001079 .queue_xmit = inet6_csk_xmit,
1080 .send_check = dccp_v6_send_check,
1081 .rebuild_header = inet6_sk_rebuild_header,
1082 .conn_request = dccp_v6_conn_request,
1083 .syn_recv_sock = dccp_v6_request_recv_sock,
1084 .net_header_len = sizeof(struct ipv6hdr),
1085 .setsockopt = ipv6_setsockopt,
1086 .getsockopt = ipv6_getsockopt,
1087 .addr2sockaddr = inet6_csk_addr2sockaddr,
1088 .sockaddr_len = sizeof(struct sockaddr_in6),
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001089#ifdef CONFIG_COMPAT
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001090 .compat_setsockopt = compat_ipv6_setsockopt,
1091 .compat_getsockopt = compat_ipv6_getsockopt,
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001092#endif
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001093};
1094
1095/*
1096 * DCCP over IPv4 via INET6 API
1097 */
1098static struct inet_connection_sock_af_ops dccp_ipv6_mapped = {
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001099 .queue_xmit = ip_queue_xmit,
1100 .send_check = dccp_v4_send_check,
1101 .rebuild_header = inet_sk_rebuild_header,
1102 .conn_request = dccp_v6_conn_request,
1103 .syn_recv_sock = dccp_v6_request_recv_sock,
1104 .net_header_len = sizeof(struct iphdr),
1105 .setsockopt = ipv6_setsockopt,
1106 .getsockopt = ipv6_getsockopt,
1107 .addr2sockaddr = inet6_csk_addr2sockaddr,
1108 .sockaddr_len = sizeof(struct sockaddr_in6),
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001109#ifdef CONFIG_COMPAT
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001110 .compat_setsockopt = compat_ipv6_setsockopt,
1111 .compat_getsockopt = compat_ipv6_getsockopt,
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001112#endif
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001113};
1114
1115/* NOTE: A lot of things set to zero explicitly by call to
1116 * sk_alloc() so need not be done here.
1117 */
1118static int dccp_v6_init_sock(struct sock *sk)
1119{
Arnaldo Carvalho de Melo72478872006-03-20 22:00:37 -08001120 static __u8 dccp_v6_ctl_sock_initialized;
1121 int err = dccp_init_sock(sk, dccp_v6_ctl_sock_initialized);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001122
Arnaldo Carvalho de Melo72478872006-03-20 22:00:37 -08001123 if (err == 0) {
1124 if (unlikely(!dccp_v6_ctl_sock_initialized))
1125 dccp_v6_ctl_sock_initialized = 1;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001126 inet_csk(sk)->icsk_af_ops = &dccp_ipv6_af_ops;
Arnaldo Carvalho de Melo72478872006-03-20 22:00:37 -08001127 }
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001128
1129 return err;
1130}
1131
1132static int dccp_v6_destroy_sock(struct sock *sk)
1133{
Arnaldo Carvalho de Melo3e0fadc2006-03-20 21:23:15 -08001134 dccp_destroy_sock(sk);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001135 return inet6_destroy_sock(sk);
1136}
1137
Gerrit Renker73c9e022006-11-10 13:01:31 -02001138static struct timewait_sock_ops dccp6_timewait_sock_ops = {
1139 .twsk_obj_size = sizeof(struct dccp6_timewait_sock),
1140};
1141
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001142static struct proto dccp_v6_prot = {
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001143 .name = "DCCPv6",
1144 .owner = THIS_MODULE,
1145 .close = dccp_close,
1146 .connect = dccp_v6_connect,
1147 .disconnect = dccp_disconnect,
1148 .ioctl = dccp_ioctl,
1149 .init = dccp_v6_init_sock,
1150 .setsockopt = dccp_setsockopt,
1151 .getsockopt = dccp_getsockopt,
1152 .sendmsg = dccp_sendmsg,
1153 .recvmsg = dccp_recvmsg,
1154 .backlog_rcv = dccp_v6_do_rcv,
1155 .hash = dccp_v6_hash,
1156 .unhash = dccp_unhash,
1157 .accept = inet_csk_accept,
1158 .get_port = dccp_v6_get_port,
1159 .shutdown = dccp_shutdown,
1160 .destroy = dccp_v6_destroy_sock,
1161 .orphan_count = &dccp_orphan_count,
1162 .max_header = MAX_DCCP_HEADER,
1163 .obj_size = sizeof(struct dccp6_sock),
1164 .rsk_prot = &dccp6_request_sock_ops,
1165 .twsk_prot = &dccp6_timewait_sock_ops,
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001166#ifdef CONFIG_COMPAT
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001167 .compat_setsockopt = compat_dccp_setsockopt,
1168 .compat_getsockopt = compat_dccp_getsockopt,
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001169#endif
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001170};
1171
1172static struct inet6_protocol dccp_v6_protocol = {
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -08001173 .handler = dccp_v6_rcv,
1174 .err_handler = dccp_v6_err,
1175 .flags = INET6_PROTO_NOPOLICY | INET6_PROTO_FINAL,
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001176};
1177
1178static struct proto_ops inet6_dccp_ops = {
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001179 .family = PF_INET6,
1180 .owner = THIS_MODULE,
1181 .release = inet6_release,
1182 .bind = inet6_bind,
1183 .connect = inet_stream_connect,
1184 .socketpair = sock_no_socketpair,
1185 .accept = inet_accept,
1186 .getname = inet6_getname,
1187 .poll = dccp_poll,
1188 .ioctl = inet6_ioctl,
1189 .listen = inet_dccp_listen,
1190 .shutdown = inet_shutdown,
1191 .setsockopt = sock_common_setsockopt,
1192 .getsockopt = sock_common_getsockopt,
1193 .sendmsg = inet_sendmsg,
1194 .recvmsg = sock_common_recvmsg,
1195 .mmap = sock_no_mmap,
1196 .sendpage = sock_no_sendpage,
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001197#ifdef CONFIG_COMPAT
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001198 .compat_setsockopt = compat_sock_common_setsockopt,
1199 .compat_getsockopt = compat_sock_common_getsockopt,
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001200#endif
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001201};
1202
1203static struct inet_protosw dccp_v6_protosw = {
1204 .type = SOCK_DCCP,
1205 .protocol = IPPROTO_DCCP,
1206 .prot = &dccp_v6_prot,
1207 .ops = &inet6_dccp_ops,
1208 .capability = -1,
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -08001209 .flags = INET_PROTOSW_ICSK,
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001210};
1211
1212static int __init dccp_v6_init(void)
1213{
1214 int err = proto_register(&dccp_v6_prot, 1);
1215
1216 if (err != 0)
1217 goto out;
1218
1219 err = inet6_add_protocol(&dccp_v6_protocol, IPPROTO_DCCP);
1220 if (err != 0)
1221 goto out_unregister_proto;
1222
1223 inet6_register_protosw(&dccp_v6_protosw);
Arnaldo Carvalho de Melo72478872006-03-20 22:00:37 -08001224
Arnaldo Carvalho de Meloc4d93902006-03-20 22:01:03 -08001225 err = inet_csk_ctl_sock_create(&dccp_v6_ctl_socket, PF_INET6,
1226 SOCK_DCCP, IPPROTO_DCCP);
1227 if (err != 0)
Arnaldo Carvalho de Melo72478872006-03-20 22:00:37 -08001228 goto out_unregister_protosw;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001229out:
1230 return err;
Arnaldo Carvalho de Melo72478872006-03-20 22:00:37 -08001231out_unregister_protosw:
1232 inet6_del_protocol(&dccp_v6_protocol, IPPROTO_DCCP);
1233 inet6_unregister_protosw(&dccp_v6_protosw);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001234out_unregister_proto:
1235 proto_unregister(&dccp_v6_prot);
1236 goto out;
1237}
1238
1239static void __exit dccp_v6_exit(void)
1240{
1241 inet6_del_protocol(&dccp_v6_protocol, IPPROTO_DCCP);
1242 inet6_unregister_protosw(&dccp_v6_protosw);
1243 proto_unregister(&dccp_v6_prot);
1244}
1245
1246module_init(dccp_v6_init);
1247module_exit(dccp_v6_exit);
1248
1249/*
1250 * __stringify doesn't likes enums, so use SOCK_DCCP (6) and IPPROTO_DCCP (33)
1251 * values directly, Also cover the case where the protocol is not specified,
1252 * i.e. net-pf-PF_INET6-proto-0-type-SOCK_DCCP
1253 */
1254MODULE_ALIAS("net-pf-" __stringify(PF_INET6) "-proto-33-type-6");
1255MODULE_ALIAS("net-pf-" __stringify(PF_INET6) "-proto-0-type-6");
1256MODULE_LICENSE("GPL");
1257MODULE_AUTHOR("Arnaldo Carvalho de Melo <acme@mandriva.com>");
1258MODULE_DESCRIPTION("DCCPv6 - Datagram Congestion Controlled Protocol");