blob: 193b946fd039587d936da2c4bb45feb43d0f6f38 [file] [log] [blame]
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001/*
2 * DCCP over IPv6
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -08003 * Linux INET6 implementation
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08004 *
5 * Based on net/dccp6/ipv6.c
6 *
7 * Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * as published by the Free Software Foundation; either version
12 * 2 of the License, or (at your option) any later version.
13 */
14
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -080015#include <linux/module.h>
16#include <linux/random.h>
17#include <linux/xfrm.h>
18
19#include <net/addrconf.h>
20#include <net/inet_common.h>
21#include <net/inet_hashtables.h>
Arnaldo Carvalho de Melo14c85022005-12-27 02:43:12 -020022#include <net/inet_sock.h>
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -080023#include <net/inet6_connection_sock.h>
24#include <net/inet6_hashtables.h>
25#include <net/ip6_route.h>
26#include <net/ipv6.h>
27#include <net/protocol.h>
28#include <net/transp_v6.h>
David S. Milleraa0e4e42006-01-06 22:55:39 -080029#include <net/ip6_checksum.h>
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -080030#include <net/xfrm.h>
31
32#include "dccp.h"
33#include "ipv6.h"
Ian McDonald4b79f0a2006-07-23 23:33:28 -070034#include "feat.h"
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -080035
Arnaldo Carvalho de Melo72478872006-03-20 22:00:37 -080036/* Socket used for sending RSTs and ACKs */
37static struct socket *dccp_v6_ctl_socket;
38
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -080039static struct inet_connection_sock_af_ops dccp_ipv6_mapped;
40static struct inet_connection_sock_af_ops dccp_ipv6_af_ops;
41
42static int dccp_v6_get_port(struct sock *sk, unsigned short snum)
43{
44 return inet_csk_get_port(&dccp_hashinfo, sk, snum,
45 inet6_csk_bind_conflict);
46}
47
48static void dccp_v6_hash(struct sock *sk)
49{
50 if (sk->sk_state != DCCP_CLOSED) {
51 if (inet_csk(sk)->icsk_af_ops == &dccp_ipv6_mapped) {
Arnaldo Carvalho de Meloc985ed72006-03-20 21:23:39 -080052 dccp_hash(sk);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -080053 return;
54 }
55 local_bh_disable();
56 __inet6_hash(&dccp_hashinfo, sk);
57 local_bh_enable();
58 }
59}
60
Gerrit Renker6f4e5ff2006-11-10 17:43:06 -020061/* add pseudo-header to DCCP checksum stored in skb->csum */
62static inline u16 dccp_v6_csum_finish(struct sk_buff *skb,
63 struct in6_addr *saddr,
64 struct in6_addr *daddr)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -080065{
Gerrit Renker6f4e5ff2006-11-10 17:43:06 -020066 return csum_ipv6_magic(saddr, daddr, skb->len, IPPROTO_DCCP, skb->csum);
67}
68
69static inline void dccp_v6_send_check(struct sock *sk, int unused_value,
70 struct sk_buff *skb)
71{
72 struct ipv6_pinfo *np = inet6_sk(sk);
73 struct dccp_hdr *dh = dccp_hdr(skb);
74
75 dccp_csum_outgoing(skb);
76 dh->dccph_checksum = dccp_v6_csum_finish(skb, &np->saddr, &np->daddr);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -080077}
78
79static __u32 dccp_v6_init_sequence(struct sock *sk, struct sk_buff *skb)
80{
81 const struct dccp_hdr *dh = dccp_hdr(skb);
82
83 if (skb->protocol == htons(ETH_P_IPV6))
84 return secure_tcpv6_sequence_number(skb->nh.ipv6h->daddr.s6_addr32,
85 skb->nh.ipv6h->saddr.s6_addr32,
86 dh->dccph_dport,
87 dh->dccph_sport);
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -080088
89 return secure_dccp_sequence_number(skb->nh.iph->daddr,
90 skb->nh.iph->saddr,
91 dh->dccph_dport,
92 dh->dccph_sport);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -080093}
94
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -080095static void dccp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
Andrea Bittau60fe62e2006-03-20 19:23:32 -080096 int type, int code, int offset, __be32 info)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -080097{
98 struct ipv6hdr *hdr = (struct ipv6hdr *)skb->data;
99 const struct dccp_hdr *dh = (struct dccp_hdr *)(skb->data + offset);
100 struct ipv6_pinfo *np;
101 struct sock *sk;
102 int err;
103 __u64 seq;
104
105 sk = inet6_lookup(&dccp_hashinfo, &hdr->daddr, dh->dccph_dport,
YOSHIFUJI Hideakif2776ff2006-11-21 17:41:56 -0800106 &hdr->saddr, dh->dccph_sport, inet6_iif(skb));
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800107
108 if (sk == NULL) {
109 ICMP6_INC_STATS_BH(__in6_dev_get(skb->dev), ICMP6_MIB_INERRORS);
110 return;
111 }
112
113 if (sk->sk_state == DCCP_TIME_WAIT) {
YOSHIFUJI Hideaki9469c7b2006-10-10 19:41:46 -0700114 inet_twsk_put(inet_twsk(sk));
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800115 return;
116 }
117
118 bh_lock_sock(sk);
119 if (sock_owned_by_user(sk))
120 NET_INC_STATS_BH(LINUX_MIB_LOCKDROPPEDICMPS);
121
122 if (sk->sk_state == DCCP_CLOSED)
123 goto out;
124
125 np = inet6_sk(sk);
126
127 if (type == ICMPV6_PKT_TOOBIG) {
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800128 struct dst_entry *dst = NULL;
129
130 if (sock_owned_by_user(sk))
131 goto out;
132 if ((1 << sk->sk_state) & (DCCPF_LISTEN | DCCPF_CLOSED))
133 goto out;
134
135 /* icmp should have updated the destination cache entry */
136 dst = __sk_dst_check(sk, np->dst_cookie);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800137 if (dst == NULL) {
138 struct inet_sock *inet = inet_sk(sk);
139 struct flowi fl;
140
141 /* BUGGG_FUTURE: Again, it is not clear how
142 to handle rthdr case. Ignore this complexity
143 for now.
144 */
145 memset(&fl, 0, sizeof(fl));
146 fl.proto = IPPROTO_DCCP;
147 ipv6_addr_copy(&fl.fl6_dst, &np->daddr);
148 ipv6_addr_copy(&fl.fl6_src, &np->saddr);
149 fl.oif = sk->sk_bound_dev_if;
150 fl.fl_ip_dport = inet->dport;
151 fl.fl_ip_sport = inet->sport;
Venkat Yekkiralabeb8d132006-08-04 23:12:42 -0700152 security_sk_classify_flow(sk, &fl);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800153
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800154 err = ip6_dst_lookup(sk, &dst, &fl);
155 if (err) {
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800156 sk->sk_err_soft = -err;
157 goto out;
158 }
159
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800160 err = xfrm_lookup(&dst, &fl, sk, 0);
161 if (err < 0) {
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800162 sk->sk_err_soft = -err;
163 goto out;
164 }
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800165 } else
166 dst_hold(dst);
167
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -0800168 if (inet_csk(sk)->icsk_pmtu_cookie > dst_mtu(dst)) {
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800169 dccp_sync_mss(sk, dst_mtu(dst));
170 } /* else let the usual retransmit timer handle it */
171 dst_release(dst);
172 goto out;
173 }
174
175 icmpv6_err_convert(type, code, &err);
176
177 seq = DCCP_SKB_CB(skb)->dccpd_seq;
178 /* Might be for an request_sock */
179 switch (sk->sk_state) {
180 struct request_sock *req, **prev;
181 case DCCP_LISTEN:
182 if (sock_owned_by_user(sk))
183 goto out;
184
185 req = inet6_csk_search_req(sk, &prev, dh->dccph_dport,
186 &hdr->daddr, &hdr->saddr,
187 inet6_iif(skb));
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800188 if (req == NULL)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800189 goto out;
190
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800191 /*
192 * ICMPs are not backlogged, hence we cannot get an established
193 * socket here.
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800194 */
195 BUG_TRAP(req->sk == NULL);
196
197 if (seq != dccp_rsk(req)->dreq_iss) {
198 NET_INC_STATS_BH(LINUX_MIB_OUTOFWINDOWICMPS);
199 goto out;
200 }
201
202 inet_csk_reqsk_queue_drop(sk, req, prev);
203 goto out;
204
205 case DCCP_REQUESTING:
206 case DCCP_RESPOND: /* Cannot happen.
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800207 It can, it SYNs are crossed. --ANK */
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800208 if (!sock_owned_by_user(sk)) {
209 DCCP_INC_STATS_BH(DCCP_MIB_ATTEMPTFAILS);
210 sk->sk_err = err;
211 /*
212 * Wake people up to see the error
213 * (see connect in sock.c)
214 */
215 sk->sk_error_report(sk);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800216 dccp_done(sk);
217 } else
218 sk->sk_err_soft = err;
219 goto out;
220 }
221
222 if (!sock_owned_by_user(sk) && np->recverr) {
223 sk->sk_err = err;
224 sk->sk_error_report(sk);
225 } else
226 sk->sk_err_soft = err;
227
228out:
229 bh_unlock_sock(sk);
230 sock_put(sk);
231}
232
233
234static int dccp_v6_send_response(struct sock *sk, struct request_sock *req,
235 struct dst_entry *dst)
236{
237 struct inet6_request_sock *ireq6 = inet6_rsk(req);
238 struct ipv6_pinfo *np = inet6_sk(sk);
239 struct sk_buff *skb;
240 struct ipv6_txoptions *opt = NULL;
241 struct in6_addr *final_p = NULL, final;
242 struct flowi fl;
243 int err = -1;
244
245 memset(&fl, 0, sizeof(fl));
246 fl.proto = IPPROTO_DCCP;
247 ipv6_addr_copy(&fl.fl6_dst, &ireq6->rmt_addr);
248 ipv6_addr_copy(&fl.fl6_src, &ireq6->loc_addr);
249 fl.fl6_flowlabel = 0;
250 fl.oif = ireq6->iif;
251 fl.fl_ip_dport = inet_rsk(req)->rmt_port;
252 fl.fl_ip_sport = inet_sk(sk)->sport;
Venkat Yekkirala4237c752006-07-24 23:32:50 -0700253 security_req_classify_flow(req, &fl);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800254
255 if (dst == NULL) {
256 opt = np->opt;
257 if (opt == NULL &&
258 np->rxopt.bits.osrcrt == 2 &&
259 ireq6->pktopts) {
260 struct sk_buff *pktopts = ireq6->pktopts;
261 struct inet6_skb_parm *rxopt = IP6CB(pktopts);
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800262
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800263 if (rxopt->srcrt)
264 opt = ipv6_invert_rthdr(sk,
265 (struct ipv6_rt_hdr *)(pktopts->nh.raw +
266 rxopt->srcrt));
267 }
268
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800269 if (opt != NULL && opt->srcrt != NULL) {
270 const struct rt0_hdr *rt0 = (struct rt0_hdr *)opt->srcrt;
271
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800272 ipv6_addr_copy(&final, &fl.fl6_dst);
273 ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
274 final_p = &final;
275 }
276
277 err = ip6_dst_lookup(sk, &dst, &fl);
278 if (err)
279 goto done;
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800280
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800281 if (final_p)
282 ipv6_addr_copy(&fl.fl6_dst, final_p);
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800283
284 err = xfrm_lookup(&dst, &fl, sk, 0);
285 if (err < 0)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800286 goto done;
287 }
288
289 skb = dccp_make_response(sk, dst, req);
290 if (skb != NULL) {
291 struct dccp_hdr *dh = dccp_hdr(skb);
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800292
Gerrit Renker6f4e5ff2006-11-10 17:43:06 -0200293 dh->dccph_checksum = dccp_v6_csum_finish(skb,
294 &ireq6->loc_addr,
295 &ireq6->rmt_addr);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800296 ipv6_addr_copy(&fl.fl6_dst, &ireq6->rmt_addr);
297 err = ip6_xmit(sk, skb, &fl, opt, 0);
298 if (err == NET_XMIT_CN)
299 err = 0;
300 }
301
302done:
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800303 if (opt != NULL && opt != np->opt)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800304 sock_kfree_s(sk, opt, opt->tot_len);
David S. Miller0cbd7822006-01-31 17:53:37 -0800305 dst_release(dst);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800306 return err;
307}
308
309static void dccp_v6_reqsk_destructor(struct request_sock *req)
310{
311 if (inet6_rsk(req)->pktopts != NULL)
312 kfree_skb(inet6_rsk(req)->pktopts);
313}
314
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800315static void dccp_v6_ctl_send_reset(struct sk_buff *rxskb)
316{
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800317 struct dccp_hdr *rxdh = dccp_hdr(rxskb), *dh;
Arnaldo Carvalho de Melo118b2c92006-03-20 22:31:09 -0800318 const u32 dccp_hdr_reset_len = sizeof(struct dccp_hdr) +
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800319 sizeof(struct dccp_hdr_ext) +
320 sizeof(struct dccp_hdr_reset);
321 struct sk_buff *skb;
322 struct flowi fl;
323 u64 seqno;
324
325 if (rxdh->dccph_type == DCCP_PKT_RESET)
326 return;
327
328 if (!ipv6_unicast_destination(rxskb))
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800329 return;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800330
Arnaldo Carvalho de Melo118b2c92006-03-20 22:31:09 -0800331 skb = alloc_skb(dccp_v6_ctl_socket->sk->sk_prot->max_header,
332 GFP_ATOMIC);
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800333 if (skb == NULL)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800334 return;
335
Arnaldo Carvalho de Melo118b2c92006-03-20 22:31:09 -0800336 skb_reserve(skb, dccp_v6_ctl_socket->sk->sk_prot->max_header);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800337
Gerrit Renker9b420782006-11-10 11:22:32 -0200338 dh = dccp_zeroed_hdr(skb, dccp_hdr_reset_len);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800339
340 /* Swap the send and the receive. */
341 dh->dccph_type = DCCP_PKT_RESET;
342 dh->dccph_sport = rxdh->dccph_dport;
343 dh->dccph_dport = rxdh->dccph_sport;
344 dh->dccph_doff = dccp_hdr_reset_len / 4;
345 dh->dccph_x = 1;
346 dccp_hdr_reset(skb)->dccph_reset_code =
347 DCCP_SKB_CB(rxskb)->dccpd_reset_code;
348
Gerrit Renker0e64e942006-10-24 16:17:51 -0700349 /* See "8.3.1. Abnormal Termination" in RFC 4340 */
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800350 seqno = 0;
351 if (DCCP_SKB_CB(rxskb)->dccpd_ack_seq != DCCP_PKT_WITHOUT_ACK_SEQ)
352 dccp_set_seqno(&seqno, DCCP_SKB_CB(rxskb)->dccpd_ack_seq + 1);
353
354 dccp_hdr_set_seq(dh, seqno);
355 dccp_hdr_set_ack(dccp_hdr_ack_bits(skb),
356 DCCP_SKB_CB(rxskb)->dccpd_seq);
357
Gerrit Renker6f4e5ff2006-11-10 17:43:06 -0200358 dccp_csum_outgoing(skb);
359 dh->dccph_checksum = dccp_v6_csum_finish(skb, &rxskb->nh.ipv6h->saddr,
360 &rxskb->nh.ipv6h->daddr);
361
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800362 memset(&fl, 0, sizeof(fl));
363 ipv6_addr_copy(&fl.fl6_dst, &rxskb->nh.ipv6h->saddr);
364 ipv6_addr_copy(&fl.fl6_src, &rxskb->nh.ipv6h->daddr);
Gerrit Renker6f4e5ff2006-11-10 17:43:06 -0200365
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800366 fl.proto = IPPROTO_DCCP;
367 fl.oif = inet6_iif(rxskb);
368 fl.fl_ip_dport = dh->dccph_dport;
369 fl.fl_ip_sport = dh->dccph_sport;
Venkat Yekkiralabeb8d132006-08-04 23:12:42 -0700370 security_skb_classify_flow(rxskb, &fl);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800371
372 /* sk = NULL, but it is safe for now. RST socket required. */
373 if (!ip6_dst_lookup(NULL, &skb->dst, &fl)) {
374 if (xfrm_lookup(&skb->dst, &fl, NULL, 0) >= 0) {
Arnaldo Carvalho de Melo72478872006-03-20 22:00:37 -0800375 ip6_xmit(dccp_v6_ctl_socket->sk, skb, &fl, NULL, 0);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800376 DCCP_INC_STATS_BH(DCCP_MIB_OUTSEGS);
377 DCCP_INC_STATS_BH(DCCP_MIB_OUTRSTS);
378 return;
379 }
380 }
381
382 kfree_skb(skb);
383}
384
Gerrit Renker73c9e022006-11-10 13:01:31 -0200385static struct request_sock_ops dccp6_request_sock_ops = {
386 .family = AF_INET6,
387 .obj_size = sizeof(struct dccp6_request_sock),
388 .rtx_syn_ack = dccp_v6_send_response,
389 .send_ack = dccp_reqsk_send_ack,
390 .destructor = dccp_v6_reqsk_destructor,
391 .send_reset = dccp_v6_ctl_send_reset,
392};
393
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800394static struct sock *dccp_v6_hnd_req(struct sock *sk,struct sk_buff *skb)
395{
396 const struct dccp_hdr *dh = dccp_hdr(skb);
397 const struct ipv6hdr *iph = skb->nh.ipv6h;
398 struct sock *nsk;
399 struct request_sock **prev;
400 /* Find possible connection requests. */
401 struct request_sock *req = inet6_csk_search_req(sk, &prev,
402 dh->dccph_sport,
403 &iph->saddr,
404 &iph->daddr,
405 inet6_iif(skb));
406 if (req != NULL)
407 return dccp_check_req(sk, skb, req, prev);
408
409 nsk = __inet6_lookup_established(&dccp_hashinfo,
410 &iph->saddr, dh->dccph_sport,
411 &iph->daddr, ntohs(dh->dccph_dport),
412 inet6_iif(skb));
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800413 if (nsk != NULL) {
414 if (nsk->sk_state != DCCP_TIME_WAIT) {
415 bh_lock_sock(nsk);
416 return nsk;
417 }
YOSHIFUJI Hideaki9469c7b2006-10-10 19:41:46 -0700418 inet_twsk_put(inet_twsk(nsk));
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800419 return NULL;
420 }
421
422 return sk;
423}
424
425static int dccp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
426{
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800427 struct request_sock *req;
428 struct dccp_request_sock *dreq;
429 struct inet6_request_sock *ireq6;
430 struct ipv6_pinfo *np = inet6_sk(sk);
Andrea Bittau60fe62e2006-03-20 19:23:32 -0800431 const __be32 service = dccp_hdr_request(skb)->dccph_req_service;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800432 struct dccp_skb_cb *dcb = DCCP_SKB_CB(skb);
433 __u8 reset_code = DCCP_RESET_CODE_TOO_BUSY;
434
435 if (skb->protocol == htons(ETH_P_IP))
436 return dccp_v4_conn_request(sk, skb);
437
438 if (!ipv6_unicast_destination(skb))
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800439 goto drop;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800440
441 if (dccp_bad_service_code(sk, service)) {
442 reset_code = DCCP_RESET_CODE_BAD_SERVICE_CODE;
443 goto drop;
444 }
445 /*
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800446 * There are no SYN attacks on IPv6, yet...
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800447 */
448 if (inet_csk_reqsk_queue_is_full(sk))
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800449 goto drop;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800450
451 if (sk_acceptq_is_full(sk) && inet_csk_reqsk_queue_young(sk) > 1)
452 goto drop;
453
Gerrit Renker82709532006-10-11 16:26:54 +0100454 req = inet6_reqsk_alloc(&dccp6_request_sock_ops);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800455 if (req == NULL)
456 goto drop;
457
Gerrit Renkercf557922006-11-10 16:08:37 -0200458 if (dccp_parse_options(sk, skb))
459 goto drop_and_free;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800460
Gerrit Renkercf557922006-11-10 16:08:37 -0200461 dccp_reqsk_init(req, skb);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800462
Venkat Yekkirala4237c752006-07-24 23:32:50 -0700463 if (security_inet_conn_request(sk, skb, req))
464 goto drop_and_free;
465
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800466 ireq6 = inet6_rsk(req);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800467 ipv6_addr_copy(&ireq6->rmt_addr, &skb->nh.ipv6h->saddr);
468 ipv6_addr_copy(&ireq6->loc_addr, &skb->nh.ipv6h->daddr);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800469 ireq6->pktopts = NULL;
470
471 if (ipv6_opt_accepted(sk, skb) ||
472 np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo ||
473 np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim) {
474 atomic_inc(&skb->users);
475 ireq6->pktopts = skb;
476 }
477 ireq6->iif = sk->sk_bound_dev_if;
478
479 /* So that link locals have meaning */
480 if (!sk->sk_bound_dev_if &&
481 ipv6_addr_type(&ireq6->rmt_addr) & IPV6_ADDR_LINKLOCAL)
482 ireq6->iif = inet6_iif(skb);
483
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800484 /*
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800485 * Step 3: Process LISTEN state
486 *
Gerrit Renkerd83ca5a2006-11-10 16:29:14 -0200487 * Set S.ISR, S.GSR, S.SWL, S.SWH from packet or Init Cookie
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800488 *
Gerrit Renkerd83ca5a2006-11-10 16:29:14 -0200489 * In fact we defer setting S.GSR, S.SWL, S.SWH to
490 * dccp_create_openreq_child.
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800491 */
492 dreq = dccp_rsk(req);
493 dreq->dreq_isr = dcb->dccpd_seq;
494 dreq->dreq_iss = dccp_v6_init_sequence(sk, skb);
495 dreq->dreq_service = service;
496
497 if (dccp_v6_send_response(sk, req, NULL))
498 goto drop_and_free;
499
500 inet6_csk_reqsk_queue_hash_add(sk, req, DCCP_TIMEOUT_INIT);
501 return 0;
502
503drop_and_free:
504 reqsk_free(req);
505drop:
506 DCCP_INC_STATS_BH(DCCP_MIB_ATTEMPTFAILS);
507 dcb->dccpd_reset_code = reset_code;
508 return -1;
509}
510
511static struct sock *dccp_v6_request_recv_sock(struct sock *sk,
512 struct sk_buff *skb,
513 struct request_sock *req,
514 struct dst_entry *dst)
515{
516 struct inet6_request_sock *ireq6 = inet6_rsk(req);
517 struct ipv6_pinfo *newnp, *np = inet6_sk(sk);
518 struct inet_sock *newinet;
519 struct dccp_sock *newdp;
520 struct dccp6_sock *newdp6;
521 struct sock *newsk;
522 struct ipv6_txoptions *opt;
523
524 if (skb->protocol == htons(ETH_P_IP)) {
525 /*
526 * v6 mapped
527 */
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800528 newsk = dccp_v4_request_recv_sock(sk, skb, req, dst);
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800529 if (newsk == NULL)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800530 return NULL;
531
532 newdp6 = (struct dccp6_sock *)newsk;
533 newdp = dccp_sk(newsk);
534 newinet = inet_sk(newsk);
535 newinet->pinet6 = &newdp6->inet6;
536 newnp = inet6_sk(newsk);
537
538 memcpy(newnp, np, sizeof(struct ipv6_pinfo));
539
540 ipv6_addr_set(&newnp->daddr, 0, 0, htonl(0x0000FFFF),
541 newinet->daddr);
542
543 ipv6_addr_set(&newnp->saddr, 0, 0, htonl(0x0000FFFF),
544 newinet->saddr);
545
546 ipv6_addr_copy(&newnp->rcv_saddr, &newnp->saddr);
547
548 inet_csk(newsk)->icsk_af_ops = &dccp_ipv6_mapped;
549 newsk->sk_backlog_rcv = dccp_v4_do_rcv;
550 newnp->pktoptions = NULL;
551 newnp->opt = NULL;
552 newnp->mcast_oif = inet6_iif(skb);
553 newnp->mcast_hops = skb->nh.ipv6h->hop_limit;
554
555 /*
556 * No need to charge this sock to the relevant IPv6 refcnt debug socks count
557 * here, dccp_create_openreq_child now does this for us, see the comment in
558 * that function for the gory details. -acme
559 */
560
561 /* It is tricky place. Until this moment IPv4 tcp
562 worked with IPv6 icsk.icsk_af_ops.
563 Sync it now.
564 */
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -0800565 dccp_sync_mss(newsk, inet_csk(newsk)->icsk_pmtu_cookie);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800566
567 return newsk;
568 }
569
570 opt = np->opt;
571
572 if (sk_acceptq_is_full(sk))
573 goto out_overflow;
574
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800575 if (np->rxopt.bits.osrcrt == 2 && opt == NULL && ireq6->pktopts) {
576 const struct inet6_skb_parm *rxopt = IP6CB(ireq6->pktopts);
577
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800578 if (rxopt->srcrt)
579 opt = ipv6_invert_rthdr(sk,
580 (struct ipv6_rt_hdr *)(ireq6->pktopts->nh.raw +
581 rxopt->srcrt));
582 }
583
584 if (dst == NULL) {
585 struct in6_addr *final_p = NULL, final;
586 struct flowi fl;
587
588 memset(&fl, 0, sizeof(fl));
589 fl.proto = IPPROTO_DCCP;
590 ipv6_addr_copy(&fl.fl6_dst, &ireq6->rmt_addr);
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800591 if (opt != NULL && opt->srcrt != NULL) {
592 const struct rt0_hdr *rt0 = (struct rt0_hdr *)opt->srcrt;
593
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800594 ipv6_addr_copy(&final, &fl.fl6_dst);
595 ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
596 final_p = &final;
597 }
598 ipv6_addr_copy(&fl.fl6_src, &ireq6->loc_addr);
599 fl.oif = sk->sk_bound_dev_if;
600 fl.fl_ip_dport = inet_rsk(req)->rmt_port;
601 fl.fl_ip_sport = inet_sk(sk)->sport;
Venkat Yekkiralabeb8d132006-08-04 23:12:42 -0700602 security_sk_classify_flow(sk, &fl);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800603
604 if (ip6_dst_lookup(sk, &dst, &fl))
605 goto out;
606
607 if (final_p)
608 ipv6_addr_copy(&fl.fl6_dst, final_p);
609
610 if ((xfrm_lookup(&dst, &fl, sk, 0)) < 0)
611 goto out;
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800612 }
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800613
614 newsk = dccp_create_openreq_child(sk, req, skb);
615 if (newsk == NULL)
616 goto out;
617
618 /*
619 * No need to charge this sock to the relevant IPv6 refcnt debug socks
620 * count here, dccp_create_openreq_child now does this for us, see the
621 * comment in that function for the gory details. -acme
622 */
623
YOSHIFUJI Hideaki8e1ef0a2006-08-29 17:15:09 -0700624 __ip6_dst_store(newsk, dst, NULL, NULL);
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800625 newsk->sk_route_caps = dst->dev->features & ~(NETIF_F_IP_CSUM |
626 NETIF_F_TSO);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800627 newdp6 = (struct dccp6_sock *)newsk;
628 newinet = inet_sk(newsk);
629 newinet->pinet6 = &newdp6->inet6;
630 newdp = dccp_sk(newsk);
631 newnp = inet6_sk(newsk);
632
633 memcpy(newnp, np, sizeof(struct ipv6_pinfo));
634
635 ipv6_addr_copy(&newnp->daddr, &ireq6->rmt_addr);
636 ipv6_addr_copy(&newnp->saddr, &ireq6->loc_addr);
637 ipv6_addr_copy(&newnp->rcv_saddr, &ireq6->loc_addr);
638 newsk->sk_bound_dev_if = ireq6->iif;
639
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800640 /* Now IPv6 options...
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800641
642 First: no IPv4 options.
643 */
644 newinet->opt = NULL;
645
646 /* Clone RX bits */
647 newnp->rxopt.all = np->rxopt.all;
648
649 /* Clone pktoptions received with SYN */
650 newnp->pktoptions = NULL;
651 if (ireq6->pktopts != NULL) {
652 newnp->pktoptions = skb_clone(ireq6->pktopts, GFP_ATOMIC);
653 kfree_skb(ireq6->pktopts);
654 ireq6->pktopts = NULL;
655 if (newnp->pktoptions)
656 skb_set_owner_r(newnp->pktoptions, newsk);
657 }
658 newnp->opt = NULL;
659 newnp->mcast_oif = inet6_iif(skb);
660 newnp->mcast_hops = skb->nh.ipv6h->hop_limit;
661
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800662 /*
663 * Clone native IPv6 options from listening socket (if any)
664 *
665 * Yes, keeping reference count would be much more clever, but we make
666 * one more one thing there: reattach optmem to newsk.
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800667 */
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800668 if (opt != NULL) {
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800669 newnp->opt = ipv6_dup_options(newsk, opt);
670 if (opt != np->opt)
671 sock_kfree_s(sk, opt, opt->tot_len);
672 }
673
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -0800674 inet_csk(newsk)->icsk_ext_hdr_len = 0;
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800675 if (newnp->opt != NULL)
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -0800676 inet_csk(newsk)->icsk_ext_hdr_len = (newnp->opt->opt_nflen +
677 newnp->opt->opt_flen);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800678
679 dccp_sync_mss(newsk, dst_mtu(dst));
680
681 newinet->daddr = newinet->saddr = newinet->rcv_saddr = LOOPBACK4_IPV6;
682
683 __inet6_hash(&dccp_hashinfo, newsk);
684 inet_inherit_port(&dccp_hashinfo, sk, newsk);
685
686 return newsk;
687
688out_overflow:
689 NET_INC_STATS_BH(LINUX_MIB_LISTENOVERFLOWS);
690out:
691 NET_INC_STATS_BH(LINUX_MIB_LISTENDROPS);
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800692 if (opt != NULL && opt != np->opt)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800693 sock_kfree_s(sk, opt, opt->tot_len);
694 dst_release(dst);
695 return NULL;
696}
697
698/* The socket must have it's spinlock held when we get
699 * here.
700 *
701 * We have a potential double-lock case here, so even when
702 * doing backlog processing we use the BH locking scheme.
703 * This is because we cannot sleep with the original spinlock
704 * held.
705 */
706static int dccp_v6_do_rcv(struct sock *sk, struct sk_buff *skb)
707{
708 struct ipv6_pinfo *np = inet6_sk(sk);
709 struct sk_buff *opt_skb = NULL;
710
711 /* Imagine: socket is IPv6. IPv4 packet arrives,
712 goes to IPv4 receive handler and backlogged.
713 From backlog it always goes here. Kerboom...
714 Fortunately, dccp_rcv_established and rcv_established
715 handle them correctly, but it is not case with
716 dccp_v6_hnd_req and dccp_v6_ctl_send_reset(). --ANK
717 */
718
719 if (skb->protocol == htons(ETH_P_IP))
720 return dccp_v4_do_rcv(sk, skb);
721
Dmitry Mishinfda9ef52006-08-31 15:28:39 -0700722 if (sk_filter(sk, skb))
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800723 goto discard;
724
725 /*
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800726 * socket locking is here for SMP purposes as backlog rcv is currently
727 * called with bh processing disabled.
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800728 */
729
730 /* Do Stevens' IPV6_PKTOPTIONS.
731
732 Yes, guys, it is the only place in our code, where we
733 may make it not affecting IPv4.
734 The rest of code is protocol independent,
735 and I do not like idea to uglify IPv4.
736
737 Actually, all the idea behind IPV6_PKTOPTIONS
738 looks not very well thought. For now we latch
739 options, received in the last packet, enqueued
740 by tcp. Feel free to propose better solution.
741 --ANK (980728)
742 */
743 if (np->rxopt.all)
Gerrit Renker89e7e572006-11-10 11:13:33 -0200744 /*
745 * FIXME: Add handling of IPV6_PKTOPTIONS skb. See the comments below
746 * (wrt ipv6_pktopions) and net/ipv6/tcp_ipv6.c for an example.
747 */
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800748 opt_skb = skb_clone(skb, GFP_ATOMIC);
749
750 if (sk->sk_state == DCCP_OPEN) { /* Fast path */
751 if (dccp_rcv_established(sk, skb, dccp_hdr(skb), skb->len))
752 goto reset;
David S. Millerfd169f12006-10-20 19:44:17 -0700753 if (opt_skb) {
Gerrit Renker89e7e572006-11-10 11:13:33 -0200754 /* XXX This is where we would goto ipv6_pktoptions. */
David S. Millerfd169f12006-10-20 19:44:17 -0700755 __kfree_skb(opt_skb);
756 }
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800757 return 0;
758 }
759
Gerrit Renkerd83ca5a2006-11-10 16:29:14 -0200760 /*
761 * Step 3: Process LISTEN state
762 * If S.state == LISTEN,
763 * If P.type == Request or P contains a valid Init Cookie option,
764 * (* Must scan the packet's options to check for Init
765 * Cookies. Only Init Cookies are processed here,
766 * however; other options are processed in Step 8. This
767 * scan need only be performed if the endpoint uses Init
768 * Cookies *)
769 * (* Generate a new socket and switch to that socket *)
770 * Set S := new socket for this port pair
771 * S.state = RESPOND
772 * Choose S.ISS (initial seqno) or set from Init Cookies
773 * Initialize S.GAR := S.ISS
774 * Set S.ISR, S.GSR, S.SWL, S.SWH from packet or Init Cookies
775 * Continue with S.state == RESPOND
776 * (* A Response packet will be generated in Step 11 *)
777 * Otherwise,
778 * Generate Reset(No Connection) unless P.type == Reset
779 * Drop packet and return
780 *
781 * NOTE: the check for the packet types is done in
782 * dccp_rcv_state_process
783 */
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800784 if (sk->sk_state == DCCP_LISTEN) {
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800785 struct sock *nsk = dccp_v6_hnd_req(sk, skb);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800786
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800787 if (nsk == NULL)
788 goto discard;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800789 /*
790 * Queue it on the new socket if the new socket is active,
791 * otherwise we just shortcircuit this and continue with
792 * the new socket..
793 */
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800794 if (nsk != sk) {
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800795 if (dccp_child_process(sk, nsk, skb))
796 goto reset;
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800797 if (opt_skb != NULL)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800798 __kfree_skb(opt_skb);
799 return 0;
800 }
801 }
802
803 if (dccp_rcv_state_process(sk, skb, dccp_hdr(skb), skb->len))
804 goto reset;
David S. Millerfd169f12006-10-20 19:44:17 -0700805 if (opt_skb) {
Gerrit Renker89e7e572006-11-10 11:13:33 -0200806 /* XXX This is where we would goto ipv6_pktoptions. */
David S. Millerfd169f12006-10-20 19:44:17 -0700807 __kfree_skb(opt_skb);
808 }
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800809 return 0;
810
811reset:
812 dccp_v6_ctl_send_reset(skb);
813discard:
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800814 if (opt_skb != NULL)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800815 __kfree_skb(opt_skb);
816 kfree_skb(skb);
817 return 0;
818}
819
Patrick McHardy951dbc82006-01-06 23:02:34 -0800820static int dccp_v6_rcv(struct sk_buff **pskb)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800821{
822 const struct dccp_hdr *dh;
823 struct sk_buff *skb = *pskb;
824 struct sock *sk;
Gerrit Renker6f4e5ff2006-11-10 17:43:06 -0200825 int min_cov;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800826
Gerrit Renker6f4e5ff2006-11-10 17:43:06 -0200827 /* Step 1: Check header basics */
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800828
829 if (dccp_invalid_packet(skb))
830 goto discard_it;
831
Gerrit Renker6f4e5ff2006-11-10 17:43:06 -0200832 /* Step 1: If header checksum is incorrect, drop packet and return. */
833 if (dccp_v6_csum_finish(skb, &skb->nh.ipv6h->saddr,
834 &skb->nh.ipv6h->daddr)) {
835 LIMIT_NETDEBUG(KERN_WARNING
836 "%s: dropped packet with invalid checksum\n",
837 __FUNCTION__);
838 goto discard_it;
839 }
840
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800841 dh = dccp_hdr(skb);
842
843 DCCP_SKB_CB(skb)->dccpd_seq = dccp_hdr_seq(skb);
844 DCCP_SKB_CB(skb)->dccpd_type = dh->dccph_type;
845
846 if (dccp_packet_without_ack(skb))
847 DCCP_SKB_CB(skb)->dccpd_ack_seq = DCCP_PKT_WITHOUT_ACK_SEQ;
848 else
849 DCCP_SKB_CB(skb)->dccpd_ack_seq = dccp_hdr_ack_seq(skb);
850
851 /* Step 2:
852 * Look up flow ID in table and get corresponding socket */
853 sk = __inet6_lookup(&dccp_hashinfo, &skb->nh.ipv6h->saddr,
854 dh->dccph_sport,
855 &skb->nh.ipv6h->daddr, ntohs(dh->dccph_dport),
856 inet6_iif(skb));
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800857 /*
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800858 * Step 2:
859 * If no socket ...
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800860 */
Gerrit Renkerd23c7102006-11-10 11:46:34 -0200861 if (sk == NULL) {
862 dccp_pr_debug("failed to look up flow ID in table and "
863 "get corresponding socket\n");
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800864 goto no_dccp_socket;
Gerrit Renkerd23c7102006-11-10 11:46:34 -0200865 }
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800866
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800867 /*
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800868 * Step 2:
869 * ... or S.state == TIMEWAIT,
870 * Generate Reset(No Connection) unless P.type == Reset
871 * Drop packet and return
872 */
Gerrit Renkerd23c7102006-11-10 11:46:34 -0200873 if (sk->sk_state == DCCP_TIME_WAIT) {
874 dccp_pr_debug("sk->sk_state == DCCP_TIME_WAIT: do_time_wait\n");
875 inet_twsk_put(inet_twsk(sk));
876 goto no_dccp_socket;
877 }
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800878
Gerrit Renker6f4e5ff2006-11-10 17:43:06 -0200879 /*
880 * RFC 4340, sec. 9.2.1: Minimum Checksum Coverage
881 * o if MinCsCov = 0, only packets with CsCov = 0 are accepted
882 * o if MinCsCov > 0, also accept packets with CsCov >= MinCsCov
883 */
884 min_cov = dccp_sk(sk)->dccps_pcrlen;
885 if (dh->dccph_cscov && (min_cov == 0 || dh->dccph_cscov < min_cov)) {
886 dccp_pr_debug("Packet CsCov %d does not satisfy MinCsCov %d\n",
887 dh->dccph_cscov, min_cov);
888 /* FIXME: send Data Dropped option (see also dccp_v4_rcv) */
889 goto discard_and_relse;
890 }
891
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800892 if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb))
893 goto discard_and_relse;
894
Arnaldo Carvalho de Melo25995ff2005-12-27 02:42:22 -0200895 return sk_receive_skb(sk, skb) ? -1 : 0;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800896
897no_dccp_socket:
898 if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb))
899 goto discard_it;
900 /*
901 * Step 2:
Gerrit Renkerd83ca5a2006-11-10 16:29:14 -0200902 * If no socket ...
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800903 * Generate Reset(No Connection) unless P.type == Reset
904 * Drop packet and return
905 */
906 if (dh->dccph_type != DCCP_PKT_RESET) {
907 DCCP_SKB_CB(skb)->dccpd_reset_code =
908 DCCP_RESET_CODE_NO_CONNECTION;
909 dccp_v6_ctl_send_reset(skb);
910 }
Gerrit Renkerd23c7102006-11-10 11:46:34 -0200911
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800912discard_it:
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800913 kfree_skb(skb);
914 return 0;
915
916discard_and_relse:
917 sock_put(sk);
918 goto discard_it;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800919}
920
Gerrit Renker73c9e022006-11-10 13:01:31 -0200921static int dccp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
922 int addr_len)
923{
924 struct sockaddr_in6 *usin = (struct sockaddr_in6 *)uaddr;
925 struct inet_connection_sock *icsk = inet_csk(sk);
926 struct inet_sock *inet = inet_sk(sk);
927 struct ipv6_pinfo *np = inet6_sk(sk);
928 struct dccp_sock *dp = dccp_sk(sk);
929 struct in6_addr *saddr = NULL, *final_p = NULL, final;
930 struct flowi fl;
931 struct dst_entry *dst;
932 int addr_type;
933 int err;
934
935 dp->dccps_role = DCCP_ROLE_CLIENT;
936
937 if (addr_len < SIN6_LEN_RFC2133)
938 return -EINVAL;
939
940 if (usin->sin6_family != AF_INET6)
941 return -EAFNOSUPPORT;
942
943 memset(&fl, 0, sizeof(fl));
944
945 if (np->sndflow) {
946 fl.fl6_flowlabel = usin->sin6_flowinfo & IPV6_FLOWINFO_MASK;
947 IP6_ECN_flow_init(fl.fl6_flowlabel);
948 if (fl.fl6_flowlabel & IPV6_FLOWLABEL_MASK) {
949 struct ip6_flowlabel *flowlabel;
950 flowlabel = fl6_sock_lookup(sk, fl.fl6_flowlabel);
951 if (flowlabel == NULL)
952 return -EINVAL;
953 ipv6_addr_copy(&usin->sin6_addr, &flowlabel->dst);
954 fl6_sock_release(flowlabel);
955 }
956 }
957 /*
958 * connect() to INADDR_ANY means loopback (BSD'ism).
959 */
960 if (ipv6_addr_any(&usin->sin6_addr))
961 usin->sin6_addr.s6_addr[15] = 1;
962
963 addr_type = ipv6_addr_type(&usin->sin6_addr);
964
965 if (addr_type & IPV6_ADDR_MULTICAST)
966 return -ENETUNREACH;
967
968 if (addr_type & IPV6_ADDR_LINKLOCAL) {
969 if (addr_len >= sizeof(struct sockaddr_in6) &&
970 usin->sin6_scope_id) {
971 /* If interface is set while binding, indices
972 * must coincide.
973 */
974 if (sk->sk_bound_dev_if &&
975 sk->sk_bound_dev_if != usin->sin6_scope_id)
976 return -EINVAL;
977
978 sk->sk_bound_dev_if = usin->sin6_scope_id;
979 }
980
981 /* Connect to link-local address requires an interface */
982 if (!sk->sk_bound_dev_if)
983 return -EINVAL;
984 }
985
986 ipv6_addr_copy(&np->daddr, &usin->sin6_addr);
987 np->flow_label = fl.fl6_flowlabel;
988
989 /*
990 * DCCP over IPv4
991 */
992 if (addr_type == IPV6_ADDR_MAPPED) {
993 u32 exthdrlen = icsk->icsk_ext_hdr_len;
994 struct sockaddr_in sin;
995
996 SOCK_DEBUG(sk, "connect: ipv4 mapped\n");
997
998 if (__ipv6_only_sock(sk))
999 return -ENETUNREACH;
1000
1001 sin.sin_family = AF_INET;
1002 sin.sin_port = usin->sin6_port;
1003 sin.sin_addr.s_addr = usin->sin6_addr.s6_addr32[3];
1004
1005 icsk->icsk_af_ops = &dccp_ipv6_mapped;
1006 sk->sk_backlog_rcv = dccp_v4_do_rcv;
1007
1008 err = dccp_v4_connect(sk, (struct sockaddr *)&sin, sizeof(sin));
1009 if (err) {
1010 icsk->icsk_ext_hdr_len = exthdrlen;
1011 icsk->icsk_af_ops = &dccp_ipv6_af_ops;
1012 sk->sk_backlog_rcv = dccp_v6_do_rcv;
1013 goto failure;
1014 } else {
1015 ipv6_addr_set(&np->saddr, 0, 0, htonl(0x0000FFFF),
1016 inet->saddr);
1017 ipv6_addr_set(&np->rcv_saddr, 0, 0, htonl(0x0000FFFF),
1018 inet->rcv_saddr);
1019 }
1020
1021 return err;
1022 }
1023
1024 if (!ipv6_addr_any(&np->rcv_saddr))
1025 saddr = &np->rcv_saddr;
1026
1027 fl.proto = IPPROTO_DCCP;
1028 ipv6_addr_copy(&fl.fl6_dst, &np->daddr);
1029 ipv6_addr_copy(&fl.fl6_src, saddr ? saddr : &np->saddr);
1030 fl.oif = sk->sk_bound_dev_if;
1031 fl.fl_ip_dport = usin->sin6_port;
1032 fl.fl_ip_sport = inet->sport;
1033 security_sk_classify_flow(sk, &fl);
1034
1035 if (np->opt != NULL && np->opt->srcrt != NULL) {
1036 const struct rt0_hdr *rt0 = (struct rt0_hdr *)np->opt->srcrt;
1037
1038 ipv6_addr_copy(&final, &fl.fl6_dst);
1039 ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
1040 final_p = &final;
1041 }
1042
1043 err = ip6_dst_lookup(sk, &dst, &fl);
1044 if (err)
1045 goto failure;
1046
1047 if (final_p)
1048 ipv6_addr_copy(&fl.fl6_dst, final_p);
1049
1050 err = xfrm_lookup(&dst, &fl, sk, 0);
1051 if (err < 0)
1052 goto failure;
1053
1054 if (saddr == NULL) {
1055 saddr = &fl.fl6_src;
1056 ipv6_addr_copy(&np->rcv_saddr, saddr);
1057 }
1058
1059 /* set the source address */
1060 ipv6_addr_copy(&np->saddr, saddr);
1061 inet->rcv_saddr = LOOPBACK4_IPV6;
1062
1063 __ip6_dst_store(sk, dst, NULL, NULL);
1064
1065 icsk->icsk_ext_hdr_len = 0;
1066 if (np->opt != NULL)
1067 icsk->icsk_ext_hdr_len = (np->opt->opt_flen +
1068 np->opt->opt_nflen);
1069
1070 inet->dport = usin->sin6_port;
1071
1072 dccp_set_state(sk, DCCP_REQUESTING);
1073 err = inet6_hash_connect(&dccp_death_row, sk);
1074 if (err)
1075 goto late_failure;
1076 /* FIXME */
1077#if 0
1078 dp->dccps_gar = secure_dccp_v6_sequence_number(np->saddr.s6_addr32,
1079 np->daddr.s6_addr32,
1080 inet->sport,
1081 inet->dport);
1082#endif
1083 err = dccp_connect(sk);
1084 if (err)
1085 goto late_failure;
1086
1087 return 0;
1088
1089late_failure:
1090 dccp_set_state(sk, DCCP_CLOSED);
1091 __sk_dst_reset(sk);
1092failure:
1093 inet->dport = 0;
1094 sk->sk_route_caps = 0;
1095 return err;
1096}
1097
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001098static struct inet_connection_sock_af_ops dccp_ipv6_af_ops = {
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001099 .queue_xmit = inet6_csk_xmit,
1100 .send_check = dccp_v6_send_check,
1101 .rebuild_header = inet6_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 ipv6hdr),
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/*
1116 * DCCP over IPv4 via INET6 API
1117 */
1118static struct inet_connection_sock_af_ops dccp_ipv6_mapped = {
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001119 .queue_xmit = ip_queue_xmit,
1120 .send_check = dccp_v4_send_check,
1121 .rebuild_header = inet_sk_rebuild_header,
1122 .conn_request = dccp_v6_conn_request,
1123 .syn_recv_sock = dccp_v6_request_recv_sock,
1124 .net_header_len = sizeof(struct iphdr),
1125 .setsockopt = ipv6_setsockopt,
1126 .getsockopt = ipv6_getsockopt,
1127 .addr2sockaddr = inet6_csk_addr2sockaddr,
1128 .sockaddr_len = sizeof(struct sockaddr_in6),
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001129#ifdef CONFIG_COMPAT
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001130 .compat_setsockopt = compat_ipv6_setsockopt,
1131 .compat_getsockopt = compat_ipv6_getsockopt,
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001132#endif
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001133};
1134
1135/* NOTE: A lot of things set to zero explicitly by call to
1136 * sk_alloc() so need not be done here.
1137 */
1138static int dccp_v6_init_sock(struct sock *sk)
1139{
Arnaldo Carvalho de Melo72478872006-03-20 22:00:37 -08001140 static __u8 dccp_v6_ctl_sock_initialized;
1141 int err = dccp_init_sock(sk, dccp_v6_ctl_sock_initialized);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001142
Arnaldo Carvalho de Melo72478872006-03-20 22:00:37 -08001143 if (err == 0) {
1144 if (unlikely(!dccp_v6_ctl_sock_initialized))
1145 dccp_v6_ctl_sock_initialized = 1;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001146 inet_csk(sk)->icsk_af_ops = &dccp_ipv6_af_ops;
Arnaldo Carvalho de Melo72478872006-03-20 22:00:37 -08001147 }
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001148
1149 return err;
1150}
1151
1152static int dccp_v6_destroy_sock(struct sock *sk)
1153{
Arnaldo Carvalho de Melo3e0fadc2006-03-20 21:23:15 -08001154 dccp_destroy_sock(sk);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001155 return inet6_destroy_sock(sk);
1156}
1157
Gerrit Renker73c9e022006-11-10 13:01:31 -02001158static struct timewait_sock_ops dccp6_timewait_sock_ops = {
1159 .twsk_obj_size = sizeof(struct dccp6_timewait_sock),
1160};
1161
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001162static struct proto dccp_v6_prot = {
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001163 .name = "DCCPv6",
1164 .owner = THIS_MODULE,
1165 .close = dccp_close,
1166 .connect = dccp_v6_connect,
1167 .disconnect = dccp_disconnect,
1168 .ioctl = dccp_ioctl,
1169 .init = dccp_v6_init_sock,
1170 .setsockopt = dccp_setsockopt,
1171 .getsockopt = dccp_getsockopt,
1172 .sendmsg = dccp_sendmsg,
1173 .recvmsg = dccp_recvmsg,
1174 .backlog_rcv = dccp_v6_do_rcv,
1175 .hash = dccp_v6_hash,
1176 .unhash = dccp_unhash,
1177 .accept = inet_csk_accept,
1178 .get_port = dccp_v6_get_port,
1179 .shutdown = dccp_shutdown,
1180 .destroy = dccp_v6_destroy_sock,
1181 .orphan_count = &dccp_orphan_count,
1182 .max_header = MAX_DCCP_HEADER,
1183 .obj_size = sizeof(struct dccp6_sock),
1184 .rsk_prot = &dccp6_request_sock_ops,
1185 .twsk_prot = &dccp6_timewait_sock_ops,
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001186#ifdef CONFIG_COMPAT
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001187 .compat_setsockopt = compat_dccp_setsockopt,
1188 .compat_getsockopt = compat_dccp_getsockopt,
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001189#endif
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001190};
1191
1192static struct inet6_protocol dccp_v6_protocol = {
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -08001193 .handler = dccp_v6_rcv,
1194 .err_handler = dccp_v6_err,
1195 .flags = INET6_PROTO_NOPOLICY | INET6_PROTO_FINAL,
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001196};
1197
1198static struct proto_ops inet6_dccp_ops = {
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001199 .family = PF_INET6,
1200 .owner = THIS_MODULE,
1201 .release = inet6_release,
1202 .bind = inet6_bind,
1203 .connect = inet_stream_connect,
1204 .socketpair = sock_no_socketpair,
1205 .accept = inet_accept,
1206 .getname = inet6_getname,
1207 .poll = dccp_poll,
1208 .ioctl = inet6_ioctl,
1209 .listen = inet_dccp_listen,
1210 .shutdown = inet_shutdown,
1211 .setsockopt = sock_common_setsockopt,
1212 .getsockopt = sock_common_getsockopt,
1213 .sendmsg = inet_sendmsg,
1214 .recvmsg = sock_common_recvmsg,
1215 .mmap = sock_no_mmap,
1216 .sendpage = sock_no_sendpage,
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001217#ifdef CONFIG_COMPAT
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001218 .compat_setsockopt = compat_sock_common_setsockopt,
1219 .compat_getsockopt = compat_sock_common_getsockopt,
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001220#endif
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001221};
1222
1223static struct inet_protosw dccp_v6_protosw = {
1224 .type = SOCK_DCCP,
1225 .protocol = IPPROTO_DCCP,
1226 .prot = &dccp_v6_prot,
1227 .ops = &inet6_dccp_ops,
1228 .capability = -1,
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -08001229 .flags = INET_PROTOSW_ICSK,
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001230};
1231
1232static int __init dccp_v6_init(void)
1233{
1234 int err = proto_register(&dccp_v6_prot, 1);
1235
1236 if (err != 0)
1237 goto out;
1238
1239 err = inet6_add_protocol(&dccp_v6_protocol, IPPROTO_DCCP);
1240 if (err != 0)
1241 goto out_unregister_proto;
1242
1243 inet6_register_protosw(&dccp_v6_protosw);
Arnaldo Carvalho de Melo72478872006-03-20 22:00:37 -08001244
Arnaldo Carvalho de Meloc4d93902006-03-20 22:01:03 -08001245 err = inet_csk_ctl_sock_create(&dccp_v6_ctl_socket, PF_INET6,
1246 SOCK_DCCP, IPPROTO_DCCP);
1247 if (err != 0)
Arnaldo Carvalho de Melo72478872006-03-20 22:00:37 -08001248 goto out_unregister_protosw;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001249out:
1250 return err;
Arnaldo Carvalho de Melo72478872006-03-20 22:00:37 -08001251out_unregister_protosw:
1252 inet6_del_protocol(&dccp_v6_protocol, IPPROTO_DCCP);
1253 inet6_unregister_protosw(&dccp_v6_protosw);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001254out_unregister_proto:
1255 proto_unregister(&dccp_v6_prot);
1256 goto out;
1257}
1258
1259static void __exit dccp_v6_exit(void)
1260{
1261 inet6_del_protocol(&dccp_v6_protocol, IPPROTO_DCCP);
1262 inet6_unregister_protosw(&dccp_v6_protosw);
1263 proto_unregister(&dccp_v6_prot);
1264}
1265
1266module_init(dccp_v6_init);
1267module_exit(dccp_v6_exit);
1268
1269/*
1270 * __stringify doesn't likes enums, so use SOCK_DCCP (6) and IPPROTO_DCCP (33)
1271 * values directly, Also cover the case where the protocol is not specified,
1272 * i.e. net-pf-PF_INET6-proto-0-type-SOCK_DCCP
1273 */
1274MODULE_ALIAS("net-pf-" __stringify(PF_INET6) "-proto-33-type-6");
1275MODULE_ALIAS("net-pf-" __stringify(PF_INET6) "-proto-0-type-6");
1276MODULE_LICENSE("GPL");
1277MODULE_AUTHOR("Arnaldo Carvalho de Melo <acme@mandriva.com>");
1278MODULE_DESCRIPTION("DCCPv6 - Datagram Congestion Controlled Protocol");