blob: 28e8252cc5ea58d260dced35c556394eef745b4f [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>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090017#include <linux/slab.h>
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -080018#include <linux/xfrm.h>
19
20#include <net/addrconf.h>
21#include <net/inet_common.h>
22#include <net/inet_hashtables.h>
Arnaldo Carvalho de Melo14c85022005-12-27 02:43:12 -020023#include <net/inet_sock.h>
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -080024#include <net/inet6_connection_sock.h>
25#include <net/inet6_hashtables.h>
26#include <net/ip6_route.h>
27#include <net/ipv6.h>
28#include <net/protocol.h>
29#include <net/transp_v6.h>
David S. Milleraa0e4e42006-01-06 22:55:39 -080030#include <net/ip6_checksum.h>
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -080031#include <net/xfrm.h>
David S. Miller6e5714e2011-08-03 20:50:44 -070032#include <net/secure_seq.h>
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -080033
34#include "dccp.h"
35#include "ipv6.h"
Ian McDonald4b79f0a2006-07-23 23:33:28 -070036#include "feat.h"
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -080037
Pavel Emelyanov13f51d82008-04-14 02:38:45 -070038/* The per-net dccp.v6_ctl_sk is used for sending RSTs and ACKs */
Arnaldo Carvalho de Melo72478872006-03-20 22:00:37 -080039
Stephen Hemminger3b401a82009-09-01 19:25:04 +000040static const struct inet_connection_sock_af_ops dccp_ipv6_mapped;
41static const struct inet_connection_sock_af_ops dccp_ipv6_af_ops;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -080042
Gerrit Renker6f4e5ff2006-11-10 17:43:06 -020043/* add pseudo-header to DCCP checksum stored in skb->csum */
Al Viro868c86b2006-11-14 21:35:48 -080044static inline __sum16 dccp_v6_csum_finish(struct sk_buff *skb,
Eric Dumazetb71d1d42011-04-22 04:53:02 +000045 const struct in6_addr *saddr,
46 const struct in6_addr *daddr)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -080047{
Gerrit Renker6f4e5ff2006-11-10 17:43:06 -020048 return csum_ipv6_magic(saddr, daddr, skb->len, IPPROTO_DCCP, skb->csum);
49}
50
Herbert Xubb296242010-04-11 02:15:55 +000051static inline void dccp_v6_send_check(struct sock *sk, struct sk_buff *skb)
Gerrit Renker6f4e5ff2006-11-10 17:43:06 -020052{
53 struct ipv6_pinfo *np = inet6_sk(sk);
54 struct dccp_hdr *dh = dccp_hdr(skb);
55
56 dccp_csum_outgoing(skb);
Eric Dumazetefe42082013-10-03 15:42:29 -070057 dh->dccph_checksum = dccp_v6_csum_finish(skb, &np->saddr, &sk->sk_v6_daddr);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -080058}
59
David S. Miller6e5714e2011-08-03 20:50:44 -070060static inline __u64 dccp_v6_init_sequence(struct sk_buff *skb)
Gerrit Renkerd7f73652006-11-13 13:34:38 -020061{
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -070062 return secure_dccpv6_sequence_number(ipv6_hdr(skb)->daddr.s6_addr32,
63 ipv6_hdr(skb)->saddr.s6_addr32,
Gerrit Renkerd7f73652006-11-13 13:34:38 -020064 dccp_hdr(skb)->dccph_dport,
65 dccp_hdr(skb)->dccph_sport );
66
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -080067}
68
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -080069static void dccp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
Brian Haleyd5fdd6b2009-06-23 04:31:07 -070070 u8 type, u8 code, int offset, __be32 info)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -080071{
Eric Dumazetb71d1d42011-04-22 04:53:02 +000072 const struct ipv6hdr *hdr = (const struct ipv6hdr *)skb->data;
Eric Dumazet1aa9d1a2016-11-02 20:30:48 -070073 const struct dccp_hdr *dh;
Wei Yongjune0bcfb02008-07-26 11:59:10 +010074 struct dccp_sock *dp;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -080075 struct ipv6_pinfo *np;
76 struct sock *sk;
77 int err;
78 __u64 seq;
Pavel Emelyanovca12a1a2008-07-16 20:28:42 -070079 struct net *net = dev_net(skb->dev);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -080080
Eric Dumazet1aa9d1a2016-11-02 20:30:48 -070081 /* Only need dccph_dport & dccph_sport which are the first
82 * 4 bytes in dccp header.
83 * Our caller (icmpv6_notify()) already pulled 8 bytes for us.
84 */
85 BUILD_BUG_ON(offsetofend(struct dccp_hdr, dccph_sport) > 8);
86 BUILD_BUG_ON(offsetofend(struct dccp_hdr, dccph_dport) > 8);
87 dh = (struct dccp_hdr *)(skb->data + offset);
Wei Yongjun860239c2008-07-26 11:59:11 +010088
Eric Dumazet52036a42015-03-22 10:22:25 -070089 sk = __inet6_lookup_established(net, &dccp_hashinfo,
90 &hdr->daddr, dh->dccph_dport,
91 &hdr->saddr, ntohs(dh->dccph_sport),
92 inet6_iif(skb));
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -080093
Eric Dumazet52036a42015-03-22 10:22:25 -070094 if (!sk) {
Eric Dumazeta16292a2016-04-27 16:44:36 -070095 __ICMP6_INC_STATS(net, __in6_dev_get(skb->dev),
96 ICMP6_MIB_INERRORS);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -080097 return;
98 }
99
100 if (sk->sk_state == DCCP_TIME_WAIT) {
YOSHIFUJI Hideaki9469c7b2006-10-10 19:41:46 -0700101 inet_twsk_put(inet_twsk(sk));
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800102 return;
103 }
Eric Dumazet52036a42015-03-22 10:22:25 -0700104 seq = dccp_hdr_seq(dh);
105 if (sk->sk_state == DCCP_NEW_SYN_RECV)
106 return dccp_req_err(sk, seq);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800107
108 bh_lock_sock(sk);
109 if (sock_owned_by_user(sk))
Eric Dumazet02a1d6e2016-04-27 16:44:39 -0700110 __NET_INC_STATS(net, LINUX_MIB_LOCKDROPPEDICMPS);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800111
112 if (sk->sk_state == DCCP_CLOSED)
113 goto out;
114
Wei Yongjune0bcfb02008-07-26 11:59:10 +0100115 dp = dccp_sk(sk);
Wei Yongjune0bcfb02008-07-26 11:59:10 +0100116 if ((1 << sk->sk_state) & ~(DCCPF_REQUESTING | DCCPF_LISTEN) &&
117 !between48(seq, dp->dccps_awl, dp->dccps_awh)) {
Eric Dumazet02a1d6e2016-04-27 16:44:39 -0700118 __NET_INC_STATS(net, LINUX_MIB_OUTOFWINDOWICMPS);
Wei Yongjune0bcfb02008-07-26 11:59:10 +0100119 goto out;
120 }
121
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800122 np = inet6_sk(sk);
123
David S. Millerec18d9a2012-07-12 00:25:15 -0700124 if (type == NDISC_REDIRECT) {
Jon Maxwell98933eb2017-03-10 16:40:33 +1100125 if (!sock_owned_by_user(sk)) {
126 struct dst_entry *dst = __sk_dst_check(sk, np->dst_cookie);
David S. Millerec18d9a2012-07-12 00:25:15 -0700127
Jon Maxwell98933eb2017-03-10 16:40:33 +1100128 if (dst)
129 dst->ops->redirect(dst, sk, skb);
130 }
Duan Jiongbd784a12013-09-18 20:03:27 +0800131 goto out;
David S. Millerec18d9a2012-07-12 00:25:15 -0700132 }
133
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800134 if (type == ICMPV6_PKT_TOOBIG) {
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800135 struct dst_entry *dst = NULL;
136
Hannes Frederic Sowa93b36cf2013-12-15 03:41:14 +0100137 if (!ip6_sk_accept_pmtu(sk))
138 goto out;
139
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800140 if (sock_owned_by_user(sk))
141 goto out;
142 if ((1 << sk->sk_state) & (DCCPF_LISTEN | DCCPF_CLOSED))
143 goto out;
144
David S. Miller35ad9b92012-07-16 03:44:56 -0700145 dst = inet6_csk_update_pmtu(sk, ntohl(info));
146 if (!dst)
147 goto out;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800148
David S. Miller35ad9b92012-07-16 03:44:56 -0700149 if (inet_csk(sk)->icsk_pmtu_cookie > dst_mtu(dst))
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800150 dccp_sync_mss(sk, dst_mtu(dst));
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800151 goto out;
152 }
153
154 icmpv6_err_convert(type, code, &err);
155
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800156 /* Might be for an request_sock */
157 switch (sk->sk_state) {
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800158 case DCCP_REQUESTING:
159 case DCCP_RESPOND: /* Cannot happen.
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800160 It can, it SYNs are crossed. --ANK */
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800161 if (!sock_owned_by_user(sk)) {
Eric Dumazetaa62d762016-04-27 16:44:28 -0700162 __DCCP_INC_STATS(DCCP_MIB_ATTEMPTFAILS);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800163 sk->sk_err = err;
164 /*
165 * Wake people up to see the error
166 * (see connect in sock.c)
167 */
168 sk->sk_error_report(sk);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800169 dccp_done(sk);
170 } else
171 sk->sk_err_soft = err;
172 goto out;
173 }
174
175 if (!sock_owned_by_user(sk) && np->recverr) {
176 sk->sk_err = err;
177 sk->sk_error_report(sk);
178 } else
179 sk->sk_err_soft = err;
180
181out:
182 bh_unlock_sock(sk);
183 sock_put(sk);
184}
185
186
Eric Dumazetea3bea32015-09-25 07:39:23 -0700187static int dccp_v6_send_response(const struct sock *sk, struct request_sock *req)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800188{
Eric Dumazet634fb9792013-10-09 15:21:29 -0700189 struct inet_request_sock *ireq = inet_rsk(req);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800190 struct ipv6_pinfo *np = inet6_sk(sk);
191 struct sk_buff *skb;
Arnaud Ebalard20c59de2010-06-01 21:35:01 +0000192 struct in6_addr *final_p, final;
David S. Miller4c9483b2011-03-12 16:22:43 -0500193 struct flowi6 fl6;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800194 int err = -1;
Denis V. Lunevfd80eb92008-02-29 11:43:03 -0800195 struct dst_entry *dst;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800196
David S. Miller4c9483b2011-03-12 16:22:43 -0500197 memset(&fl6, 0, sizeof(fl6));
198 fl6.flowi6_proto = IPPROTO_DCCP;
Eric Dumazet634fb9792013-10-09 15:21:29 -0700199 fl6.daddr = ireq->ir_v6_rmt_addr;
200 fl6.saddr = ireq->ir_v6_loc_addr;
David S. Miller4c9483b2011-03-12 16:22:43 -0500201 fl6.flowlabel = 0;
Eric Dumazet634fb9792013-10-09 15:21:29 -0700202 fl6.flowi6_oif = ireq->ir_iif;
203 fl6.fl6_dport = ireq->ir_rmt_port;
Eric Dumazetb44084c2013-10-10 00:04:37 -0700204 fl6.fl6_sport = htons(ireq->ir_num);
David S. Miller4c9483b2011-03-12 16:22:43 -0500205 security_req_classify_flow(req, flowi6_to_flowi(&fl6));
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800206
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800207
Eric Dumazet45f6fad2015-11-29 19:37:57 -0800208 rcu_read_lock();
209 final_p = fl6_update_dst(&fl6, rcu_dereference(np->opt), &final);
210 rcu_read_unlock();
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800211
Steffen Klassert0e0d44a2013-08-28 08:04:14 +0200212 dst = ip6_dst_lookup_flow(sk, &fl6, final_p);
David S. Miller68d0c6d2011-03-01 13:19:07 -0800213 if (IS_ERR(dst)) {
214 err = PTR_ERR(dst);
215 dst = NULL;
Denis V. Lunevfd80eb92008-02-29 11:43:03 -0800216 goto done;
David S. Miller68d0c6d2011-03-01 13:19:07 -0800217 }
Denis V. Lunevfd80eb92008-02-29 11:43:03 -0800218
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800219 skb = dccp_make_response(sk, dst, req);
220 if (skb != NULL) {
221 struct dccp_hdr *dh = dccp_hdr(skb);
Huw Davies56ac42b2016-06-27 15:05:28 -0400222 struct ipv6_txoptions *opt;
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800223
Gerrit Renker6f4e5ff2006-11-10 17:43:06 -0200224 dh->dccph_checksum = dccp_v6_csum_finish(skb,
Eric Dumazet634fb9792013-10-09 15:21:29 -0700225 &ireq->ir_v6_loc_addr,
226 &ireq->ir_v6_rmt_addr);
227 fl6.daddr = ireq->ir_v6_rmt_addr;
Eric Dumazet45f6fad2015-11-29 19:37:57 -0800228 rcu_read_lock();
Huw Davies56ac42b2016-06-27 15:05:28 -0400229 opt = ireq->ipv6_opt;
230 if (!opt)
231 opt = rcu_dereference(np->opt);
Pablo Neira0d4c19e2017-01-26 22:56:21 +0100232 err = ip6_xmit(sk, skb, &fl6, sk->sk_mark, opt, np->tclass);
Eric Dumazet45f6fad2015-11-29 19:37:57 -0800233 rcu_read_unlock();
Gerrit Renkerb9df3cb2006-11-14 11:21:36 -0200234 err = net_xmit_eval(err);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800235 }
236
237done:
David S. Miller0cbd7822006-01-31 17:53:37 -0800238 dst_release(dst);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800239 return err;
240}
241
242static void dccp_v6_reqsk_destructor(struct request_sock *req)
243{
Gerrit Renkerd99a7bd2008-11-04 23:56:30 -0800244 dccp_feat_list_purge(&dccp_rsk(req)->dreq_featneg);
Huw Davies56ac42b2016-06-27 15:05:28 -0400245 kfree(inet_rsk(req)->ipv6_opt);
Eric Dumazet634fb9792013-10-09 15:21:29 -0700246 kfree_skb(inet_rsk(req)->pktopts);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800247}
248
Eric Dumazeta00e7442015-09-29 07:42:39 -0700249static void dccp_v6_ctl_send_reset(const struct sock *sk, struct sk_buff *rxskb)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800250{
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000251 const struct ipv6hdr *rxip6h;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800252 struct sk_buff *skb;
David S. Miller4c9483b2011-03-12 16:22:43 -0500253 struct flowi6 fl6;
Eric Dumazetadf30902009-06-02 05:19:30 +0000254 struct net *net = dev_net(skb_dst(rxskb)->dev);
Pavel Emelyanov334527d2008-04-13 22:32:45 -0700255 struct sock *ctl_sk = net->dccp.v6_ctl_sk;
Eric Dumazetadf30902009-06-02 05:19:30 +0000256 struct dst_entry *dst;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800257
Gerrit Renkere356d372007-09-26 14:35:19 -0300258 if (dccp_hdr(rxskb)->dccph_type == DCCP_PKT_RESET)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800259 return;
260
261 if (!ipv6_unicast_destination(rxskb))
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800262 return;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800263
Pavel Emelyanov02047742008-04-13 22:32:25 -0700264 skb = dccp_ctl_make_reset(ctl_sk, rxskb);
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800265 if (skb == NULL)
Arnaldo Carvalho de Melo8109b022006-12-10 16:01:18 -0200266 return;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800267
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700268 rxip6h = ipv6_hdr(rxskb);
Gerrit Renkere356d372007-09-26 14:35:19 -0300269 dccp_hdr(skb)->dccph_checksum = dccp_v6_csum_finish(skb, &rxip6h->saddr,
270 &rxip6h->daddr);
Gerrit Renker6f4e5ff2006-11-10 17:43:06 -0200271
David S. Miller4c9483b2011-03-12 16:22:43 -0500272 memset(&fl6, 0, sizeof(fl6));
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +0000273 fl6.daddr = rxip6h->saddr;
274 fl6.saddr = rxip6h->daddr;
Gerrit Renker6f4e5ff2006-11-10 17:43:06 -0200275
David S. Miller4c9483b2011-03-12 16:22:43 -0500276 fl6.flowi6_proto = IPPROTO_DCCP;
277 fl6.flowi6_oif = inet6_iif(rxskb);
David S. Miller1958b852011-03-12 16:36:19 -0500278 fl6.fl6_dport = dccp_hdr(skb)->dccph_dport;
279 fl6.fl6_sport = dccp_hdr(skb)->dccph_sport;
David S. Miller4c9483b2011-03-12 16:22:43 -0500280 security_skb_classify_flow(rxskb, flowi6_to_flowi(&fl6));
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800281
282 /* sk = NULL, but it is safe for now. RST socket required. */
Steffen Klassert0e0d44a2013-08-28 08:04:14 +0200283 dst = ip6_dst_lookup_flow(ctl_sk, &fl6, NULL);
David S. Miller68d0c6d2011-03-01 13:19:07 -0800284 if (!IS_ERR(dst)) {
285 skb_dst_set(skb, dst);
Pablo Neira0d4c19e2017-01-26 22:56:21 +0100286 ip6_xmit(ctl_sk, skb, &fl6, 0, NULL, 0);
Eric Dumazet7309f882016-04-29 14:16:49 -0700287 DCCP_INC_STATS(DCCP_MIB_OUTSEGS);
288 DCCP_INC_STATS(DCCP_MIB_OUTRSTS);
David S. Miller68d0c6d2011-03-01 13:19:07 -0800289 return;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800290 }
291
292 kfree_skb(skb);
293}
294
Gerrit Renker73c9e022006-11-10 13:01:31 -0200295static struct request_sock_ops dccp6_request_sock_ops = {
296 .family = AF_INET6,
297 .obj_size = sizeof(struct dccp6_request_sock),
298 .rtx_syn_ack = dccp_v6_send_response,
299 .send_ack = dccp_reqsk_send_ack,
300 .destructor = dccp_v6_reqsk_destructor,
301 .send_reset = dccp_v6_ctl_send_reset,
Eric Dumazetc72e1182012-04-12 22:16:05 +0000302 .syn_ack_timeout = dccp_syn_ack_timeout,
Gerrit Renker73c9e022006-11-10 13:01:31 -0200303};
304
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800305static int dccp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
306{
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800307 struct request_sock *req;
308 struct dccp_request_sock *dreq;
Eric Dumazet634fb9792013-10-09 15:21:29 -0700309 struct inet_request_sock *ireq;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800310 struct ipv6_pinfo *np = inet6_sk(sk);
Arnaldo Carvalho de Melo8109b022006-12-10 16:01:18 -0200311 const __be32 service = dccp_hdr_request(skb)->dccph_req_service;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800312 struct dccp_skb_cb *dcb = DCCP_SKB_CB(skb);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800313
314 if (skb->protocol == htons(ETH_P_IP))
315 return dccp_v4_conn_request(sk, skb);
316
317 if (!ipv6_unicast_destination(skb))
Gerrit Renker4a5409a2007-10-04 14:52:28 -0700318 return 0; /* discard, don't send a reset here */
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800319
320 if (dccp_bad_service_code(sk, service)) {
Gerrit Renker4a5409a2007-10-04 14:52:28 -0700321 dcb->dccpd_reset_code = DCCP_RESET_CODE_BAD_SERVICE_CODE;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800322 goto drop;
Arnaldo Carvalho de Melo8109b022006-12-10 16:01:18 -0200323 }
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800324 /*
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800325 * There are no SYN attacks on IPv6, yet...
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800326 */
Gerrit Renker4a5409a2007-10-04 14:52:28 -0700327 dcb->dccpd_reset_code = DCCP_RESET_CODE_TOO_BUSY;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800328 if (inet_csk_reqsk_queue_is_full(sk))
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800329 goto drop;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800330
331 if (sk_acceptq_is_full(sk) && inet_csk_reqsk_queue_young(sk) > 1)
332 goto drop;
333
Eric Dumazeta1a53442015-10-04 21:08:11 -0700334 req = inet_reqsk_alloc(&dccp6_request_sock_ops, sk, true);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800335 if (req == NULL)
336 goto drop;
337
Gerrit Renkerac757732008-11-04 23:55:49 -0800338 if (dccp_reqsk_init(req, dccp_sk(sk), skb))
339 goto drop_and_free;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800340
Gerrit Renker8b819412007-12-13 12:29:24 -0200341 dreq = dccp_rsk(req);
342 if (dccp_parse_options(sk, dreq, skb))
343 goto drop_and_free;
344
Venkat Yekkirala4237c752006-07-24 23:32:50 -0700345 if (security_inet_conn_request(sk, skb, req))
346 goto drop_and_free;
347
Eric Dumazet634fb9792013-10-09 15:21:29 -0700348 ireq = inet_rsk(req);
349 ireq->ir_v6_rmt_addr = ipv6_hdr(skb)->saddr;
350 ireq->ir_v6_loc_addr = ipv6_hdr(skb)->daddr;
Eric Dumazet3f66b082015-03-12 16:44:10 -0700351 ireq->ireq_family = AF_INET6;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800352
Eric Dumazeta2247722014-09-27 09:50:56 -0700353 if (ipv6_opt_accepted(sk, skb, IP6CB(skb)) ||
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800354 np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo ||
355 np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim) {
356 atomic_inc(&skb->users);
Eric Dumazet634fb9792013-10-09 15:21:29 -0700357 ireq->pktopts = skb;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800358 }
Eric Dumazet634fb9792013-10-09 15:21:29 -0700359 ireq->ir_iif = sk->sk_bound_dev_if;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800360
361 /* So that link locals have meaning */
362 if (!sk->sk_bound_dev_if &&
Eric Dumazet634fb9792013-10-09 15:21:29 -0700363 ipv6_addr_type(&ireq->ir_v6_rmt_addr) & IPV6_ADDR_LINKLOCAL)
364 ireq->ir_iif = inet6_iif(skb);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800365
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800366 /*
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800367 * Step 3: Process LISTEN state
368 *
Gerrit Renkerd83ca5a2006-11-10 16:29:14 -0200369 * Set S.ISR, S.GSR, S.SWL, S.SWH from packet or Init Cookie
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800370 *
Samuel Jerof541fb72012-02-26 18:22:02 -0700371 * Setting S.SWL/S.SWH to is deferred to dccp_create_openreq_child().
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800372 */
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800373 dreq->dreq_isr = dcb->dccpd_seq;
Samuel Jerof541fb72012-02-26 18:22:02 -0700374 dreq->dreq_gsr = dreq->dreq_isr;
Gerrit Renker865e9022006-11-13 13:31:50 -0200375 dreq->dreq_iss = dccp_v6_init_sequence(skb);
Samuel Jerof541fb72012-02-26 18:22:02 -0700376 dreq->dreq_gss = dreq->dreq_iss;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800377 dreq->dreq_service = service;
378
Christoph Paasch1a2c6182013-03-17 08:23:34 +0000379 if (dccp_v6_send_response(sk, req))
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800380 goto drop_and_free;
381
Eric Dumazet079096f2015-10-02 11:43:32 -0700382 inet_csk_reqsk_queue_hash_add(sk, req, DCCP_TIMEOUT_INIT);
Xin Long9ffa6722017-07-26 14:19:09 +0800383 reqsk_put(req);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800384 return 0;
385
386drop_and_free:
387 reqsk_free(req);
388drop:
Eric Dumazetaa62d762016-04-27 16:44:28 -0700389 __DCCP_INC_STATS(DCCP_MIB_ATTEMPTFAILS);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800390 return -1;
391}
392
Eric Dumazet0c271712015-09-29 07:42:48 -0700393static struct sock *dccp_v6_request_recv_sock(const struct sock *sk,
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800394 struct sk_buff *skb,
395 struct request_sock *req,
Eric Dumazet5e0724d2015-10-22 08:20:46 -0700396 struct dst_entry *dst,
397 struct request_sock *req_unhash,
398 bool *own_req)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800399{
Eric Dumazet634fb9792013-10-09 15:21:29 -0700400 struct inet_request_sock *ireq = inet_rsk(req);
Eric Dumazet0c271712015-09-29 07:42:48 -0700401 struct ipv6_pinfo *newnp;
402 const struct ipv6_pinfo *np = inet6_sk(sk);
Eric Dumazet45f6fad2015-11-29 19:37:57 -0800403 struct ipv6_txoptions *opt;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800404 struct inet_sock *newinet;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800405 struct dccp6_sock *newdp6;
406 struct sock *newsk;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800407
408 if (skb->protocol == htons(ETH_P_IP)) {
409 /*
410 * v6 mapped
411 */
Eric Dumazet5e0724d2015-10-22 08:20:46 -0700412 newsk = dccp_v4_request_recv_sock(sk, skb, req, dst,
413 req_unhash, own_req);
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800414 if (newsk == NULL)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800415 return NULL;
416
417 newdp6 = (struct dccp6_sock *)newsk;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800418 newinet = inet_sk(newsk);
419 newinet->pinet6 = &newdp6->inet6;
420 newnp = inet6_sk(newsk);
421
422 memcpy(newnp, np, sizeof(struct ipv6_pinfo));
423
Eric Dumazetd1e559d2015-03-18 14:05:35 -0700424 newnp->saddr = newsk->sk_v6_rcv_saddr;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800425
426 inet_csk(newsk)->icsk_af_ops = &dccp_ipv6_mapped;
427 newsk->sk_backlog_rcv = dccp_v4_do_rcv;
428 newnp->pktoptions = NULL;
429 newnp->opt = NULL;
WANG Cong4bd8f5e2017-05-09 16:59:54 -0700430 newnp->ipv6_mc_list = NULL;
431 newnp->ipv6_ac_list = NULL;
432 newnp->ipv6_fl_list = NULL;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800433 newnp->mcast_oif = inet6_iif(skb);
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700434 newnp->mcast_hops = ipv6_hdr(skb)->hop_limit;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800435
436 /*
437 * No need to charge this sock to the relevant IPv6 refcnt debug socks count
438 * here, dccp_create_openreq_child now does this for us, see the comment in
439 * that function for the gory details. -acme
440 */
441
442 /* It is tricky place. Until this moment IPv4 tcp
443 worked with IPv6 icsk.icsk_af_ops.
444 Sync it now.
445 */
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -0800446 dccp_sync_mss(newsk, inet_csk(newsk)->icsk_pmtu_cookie);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800447
448 return newsk;
449 }
450
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800451
452 if (sk_acceptq_is_full(sk))
453 goto out_overflow;
454
Eric Dumazetf76b33c2015-09-29 07:42:42 -0700455 if (!dst) {
David S. Miller4c9483b2011-03-12 16:22:43 -0500456 struct flowi6 fl6;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800457
Eric Dumazetf76b33c2015-09-29 07:42:42 -0700458 dst = inet6_csk_route_req(sk, &fl6, req, IPPROTO_DCCP);
459 if (!dst)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800460 goto out;
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800461 }
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800462
463 newsk = dccp_create_openreq_child(sk, req, skb);
464 if (newsk == NULL)
Balazs Scheidler093d2822010-10-21 13:06:43 +0200465 goto out_nonewsk;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800466
467 /*
468 * No need to charge this sock to the relevant IPv6 refcnt debug socks
469 * count here, dccp_create_openreq_child now does this for us, see the
470 * comment in that function for the gory details. -acme
471 */
472
Eric Dumazet6bd4f352015-12-02 21:53:57 -0800473 ip6_dst_store(newsk, dst, NULL, NULL);
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800474 newsk->sk_route_caps = dst->dev->features & ~(NETIF_F_IP_CSUM |
475 NETIF_F_TSO);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800476 newdp6 = (struct dccp6_sock *)newsk;
477 newinet = inet_sk(newsk);
478 newinet->pinet6 = &newdp6->inet6;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800479 newnp = inet6_sk(newsk);
480
481 memcpy(newnp, np, sizeof(struct ipv6_pinfo));
482
Eric Dumazet634fb9792013-10-09 15:21:29 -0700483 newsk->sk_v6_daddr = ireq->ir_v6_rmt_addr;
484 newnp->saddr = ireq->ir_v6_loc_addr;
485 newsk->sk_v6_rcv_saddr = ireq->ir_v6_loc_addr;
486 newsk->sk_bound_dev_if = ireq->ir_iif;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800487
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800488 /* Now IPv6 options...
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800489
490 First: no IPv4 options.
491 */
Eric Dumazetf6d8bd02011-04-21 09:45:37 +0000492 newinet->inet_opt = NULL;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800493
494 /* Clone RX bits */
495 newnp->rxopt.all = np->rxopt.all;
496
WANG Cong4bd8f5e2017-05-09 16:59:54 -0700497 newnp->ipv6_mc_list = NULL;
498 newnp->ipv6_ac_list = NULL;
499 newnp->ipv6_fl_list = NULL;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800500 newnp->pktoptions = NULL;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800501 newnp->opt = NULL;
502 newnp->mcast_oif = inet6_iif(skb);
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700503 newnp->mcast_hops = ipv6_hdr(skb)->hop_limit;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800504
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800505 /*
506 * Clone native IPv6 options from listening socket (if any)
507 *
508 * Yes, keeping reference count would be much more clever, but we make
509 * one more one thing there: reattach optmem to newsk.
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800510 */
Huw Davies56ac42b2016-06-27 15:05:28 -0400511 opt = ireq->ipv6_opt;
512 if (!opt)
513 opt = rcu_dereference(np->opt);
Eric Dumazet45f6fad2015-11-29 19:37:57 -0800514 if (opt) {
515 opt = ipv6_dup_options(newsk, opt);
516 RCU_INIT_POINTER(newnp->opt, opt);
517 }
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -0800518 inet_csk(newsk)->icsk_ext_hdr_len = 0;
Eric Dumazet45f6fad2015-11-29 19:37:57 -0800519 if (opt)
520 inet_csk(newsk)->icsk_ext_hdr_len = opt->opt_nflen +
521 opt->opt_flen;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800522
523 dccp_sync_mss(newsk, dst_mtu(dst));
524
Eric Dumazetc720c7e2009-10-15 06:30:45 +0000525 newinet->inet_daddr = newinet->inet_saddr = LOOPBACK4_IPV6;
526 newinet->inet_rcv_saddr = LOOPBACK4_IPV6;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800527
Balazs Scheidler093d2822010-10-21 13:06:43 +0200528 if (__inet_inherit_port(sk, newsk) < 0) {
Christoph Paasche337e242012-12-14 04:07:58 +0000529 inet_csk_prepare_forced_close(newsk);
530 dccp_done(newsk);
Balazs Scheidler093d2822010-10-21 13:06:43 +0200531 goto out;
532 }
Eric Dumazet5e0724d2015-10-22 08:20:46 -0700533 *own_req = inet_ehash_nolisten(newsk, req_to_sk(req_unhash));
Eric Dumazetce105002015-10-30 09:46:12 -0700534 /* Clone pktoptions received with SYN, if we own the req */
535 if (*own_req && ireq->pktopts) {
536 newnp->pktoptions = skb_clone(ireq->pktopts, GFP_ATOMIC);
537 consume_skb(ireq->pktopts);
538 ireq->pktopts = NULL;
539 if (newnp->pktoptions)
540 skb_set_owner_r(newnp->pktoptions, newsk);
541 }
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800542
543 return newsk;
544
545out_overflow:
Eric Dumazet02a1d6e2016-04-27 16:44:39 -0700546 __NET_INC_STATS(sock_net(sk), LINUX_MIB_LISTENOVERFLOWS);
Balazs Scheidler093d2822010-10-21 13:06:43 +0200547out_nonewsk:
548 dst_release(dst);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800549out:
Eric Dumazet02a1d6e2016-04-27 16:44:39 -0700550 __NET_INC_STATS(sock_net(sk), LINUX_MIB_LISTENDROPS);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800551 return NULL;
552}
553
554/* The socket must have it's spinlock held when we get
555 * here.
556 *
557 * We have a potential double-lock case here, so even when
558 * doing backlog processing we use the BH locking scheme.
559 * This is because we cannot sleep with the original spinlock
560 * held.
561 */
562static int dccp_v6_do_rcv(struct sock *sk, struct sk_buff *skb)
563{
564 struct ipv6_pinfo *np = inet6_sk(sk);
565 struct sk_buff *opt_skb = NULL;
566
567 /* Imagine: socket is IPv6. IPv4 packet arrives,
568 goes to IPv4 receive handler and backlogged.
569 From backlog it always goes here. Kerboom...
570 Fortunately, dccp_rcv_established and rcv_established
571 handle them correctly, but it is not case with
572 dccp_v6_hnd_req and dccp_v6_ctl_send_reset(). --ANK
573 */
574
575 if (skb->protocol == htons(ETH_P_IP))
576 return dccp_v4_do_rcv(sk, skb);
577
Dmitry Mishinfda9ef52006-08-31 15:28:39 -0700578 if (sk_filter(sk, skb))
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800579 goto discard;
580
581 /*
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800582 * socket locking is here for SMP purposes as backlog rcv is currently
583 * called with bh processing disabled.
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800584 */
585
586 /* Do Stevens' IPV6_PKTOPTIONS.
587
588 Yes, guys, it is the only place in our code, where we
589 may make it not affecting IPv4.
590 The rest of code is protocol independent,
591 and I do not like idea to uglify IPv4.
592
593 Actually, all the idea behind IPV6_PKTOPTIONS
594 looks not very well thought. For now we latch
595 options, received in the last packet, enqueued
596 by tcp. Feel free to propose better solution.
YOSHIFUJI Hideakic9eaf172007-02-09 23:24:38 +0900597 --ANK (980728)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800598 */
599 if (np->rxopt.all)
Gerrit Renker89e7e572006-11-10 11:13:33 -0200600 /*
601 * FIXME: Add handling of IPV6_PKTOPTIONS skb. See the comments below
602 * (wrt ipv6_pktopions) and net/ipv6/tcp_ipv6.c for an example.
603 */
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800604 opt_skb = skb_clone(skb, GFP_ATOMIC);
605
606 if (sk->sk_state == DCCP_OPEN) { /* Fast path */
607 if (dccp_rcv_established(sk, skb, dccp_hdr(skb), skb->len))
608 goto reset;
David S. Millerfd169f12006-10-20 19:44:17 -0700609 if (opt_skb) {
Gerrit Renker89e7e572006-11-10 11:13:33 -0200610 /* XXX This is where we would goto ipv6_pktoptions. */
David S. Millerfd169f12006-10-20 19:44:17 -0700611 __kfree_skb(opt_skb);
612 }
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800613 return 0;
614 }
615
Gerrit Renkerd83ca5a2006-11-10 16:29:14 -0200616 /*
617 * Step 3: Process LISTEN state
618 * If S.state == LISTEN,
619 * If P.type == Request or P contains a valid Init Cookie option,
620 * (* Must scan the packet's options to check for Init
621 * Cookies. Only Init Cookies are processed here,
622 * however; other options are processed in Step 8. This
623 * scan need only be performed if the endpoint uses Init
624 * Cookies *)
625 * (* Generate a new socket and switch to that socket *)
626 * Set S := new socket for this port pair
627 * S.state = RESPOND
628 * Choose S.ISS (initial seqno) or set from Init Cookies
629 * Initialize S.GAR := S.ISS
630 * Set S.ISR, S.GSR, S.SWL, S.SWH from packet or Init Cookies
631 * Continue with S.state == RESPOND
632 * (* A Response packet will be generated in Step 11 *)
633 * Otherwise,
634 * Generate Reset(No Connection) unless P.type == Reset
635 * Drop packet and return
636 *
637 * NOTE: the check for the packet types is done in
638 * dccp_rcv_state_process
639 */
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800640
641 if (dccp_rcv_state_process(sk, skb, dccp_hdr(skb), skb->len))
642 goto reset;
David S. Millerfd169f12006-10-20 19:44:17 -0700643 if (opt_skb) {
Gerrit Renker89e7e572006-11-10 11:13:33 -0200644 /* XXX This is where we would goto ipv6_pktoptions. */
David S. Millerfd169f12006-10-20 19:44:17 -0700645 __kfree_skb(opt_skb);
646 }
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800647 return 0;
648
649reset:
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800650 dccp_v6_ctl_send_reset(sk, skb);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800651discard:
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800652 if (opt_skb != NULL)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800653 __kfree_skb(opt_skb);
654 kfree_skb(skb);
655 return 0;
656}
657
Herbert Xue5bbef22007-10-15 12:50:28 -0700658static int dccp_v6_rcv(struct sk_buff *skb)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800659{
660 const struct dccp_hdr *dh;
Eric Dumazet3b24d852016-04-01 08:52:17 -0700661 bool refcounted;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800662 struct sock *sk;
Gerrit Renker6f4e5ff2006-11-10 17:43:06 -0200663 int min_cov;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800664
Gerrit Renker6f4e5ff2006-11-10 17:43:06 -0200665 /* Step 1: Check header basics */
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800666
667 if (dccp_invalid_packet(skb))
668 goto discard_it;
669
Gerrit Renker6f4e5ff2006-11-10 17:43:06 -0200670 /* Step 1: If header checksum is incorrect, drop packet and return. */
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700671 if (dccp_v6_csum_finish(skb, &ipv6_hdr(skb)->saddr,
672 &ipv6_hdr(skb)->daddr)) {
Gerrit Renker59348b12006-11-20 18:39:23 -0200673 DCCP_WARN("dropped packet with invalid checksum\n");
Gerrit Renker6f4e5ff2006-11-10 17:43:06 -0200674 goto discard_it;
675 }
676
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800677 dh = dccp_hdr(skb);
678
Gerrit Renkerfde20102007-10-24 10:12:09 -0200679 DCCP_SKB_CB(skb)->dccpd_seq = dccp_hdr_seq(dh);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800680 DCCP_SKB_CB(skb)->dccpd_type = dh->dccph_type;
681
682 if (dccp_packet_without_ack(skb))
683 DCCP_SKB_CB(skb)->dccpd_ack_seq = DCCP_PKT_WITHOUT_ACK_SEQ;
684 else
685 DCCP_SKB_CB(skb)->dccpd_ack_seq = dccp_hdr_ack_seq(skb);
686
Eric Dumazet4bdc3d62015-10-13 17:12:54 -0700687lookup:
Craig Galleka5836362016-02-10 11:50:38 -0500688 sk = __inet6_lookup_skb(&dccp_hashinfo, skb, __dccp_hdr_len(dh),
Eric Dumazet870c3152014-10-17 09:17:20 -0700689 dh->dccph_sport, dh->dccph_dport,
Eric Dumazet3b24d852016-04-01 08:52:17 -0700690 inet6_iif(skb), &refcounted);
Eric Dumazet4bdc3d62015-10-13 17:12:54 -0700691 if (!sk) {
Gerrit Renkerd23c7102006-11-10 11:46:34 -0200692 dccp_pr_debug("failed to look up flow ID in table and "
693 "get corresponding socket\n");
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800694 goto no_dccp_socket;
Gerrit Renkerd23c7102006-11-10 11:46:34 -0200695 }
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800696
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800697 /*
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800698 * Step 2:
Arnaldo Carvalho de Melo8109b022006-12-10 16:01:18 -0200699 * ... or S.state == TIMEWAIT,
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800700 * Generate Reset(No Connection) unless P.type == Reset
701 * Drop packet and return
702 */
Gerrit Renkerd23c7102006-11-10 11:46:34 -0200703 if (sk->sk_state == DCCP_TIME_WAIT) {
704 dccp_pr_debug("sk->sk_state == DCCP_TIME_WAIT: do_time_wait\n");
705 inet_twsk_put(inet_twsk(sk));
706 goto no_dccp_socket;
707 }
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800708
Eric Dumazet079096f2015-10-02 11:43:32 -0700709 if (sk->sk_state == DCCP_NEW_SYN_RECV) {
710 struct request_sock *req = inet_reqsk(sk);
Eric Dumazet77166822016-02-18 05:39:18 -0800711 struct sock *nsk;
Eric Dumazet079096f2015-10-02 11:43:32 -0700712
713 sk = req->rsk_listener;
Eric Dumazet77166822016-02-18 05:39:18 -0800714 if (unlikely(sk->sk_state != DCCP_LISTEN)) {
Eric Dumazetf03f2e12015-10-14 11:16:27 -0700715 inet_csk_reqsk_queue_drop_and_put(sk, req);
Eric Dumazet4bdc3d62015-10-13 17:12:54 -0700716 goto lookup;
717 }
Eric Dumazet77166822016-02-18 05:39:18 -0800718 sock_hold(sk);
Eric Dumazet3b24d852016-04-01 08:52:17 -0700719 refcounted = true;
Eric Dumazet77166822016-02-18 05:39:18 -0800720 nsk = dccp_check_req(sk, skb, req);
Eric Dumazet079096f2015-10-02 11:43:32 -0700721 if (!nsk) {
722 reqsk_put(req);
Eric Dumazet77166822016-02-18 05:39:18 -0800723 goto discard_and_relse;
Eric Dumazet079096f2015-10-02 11:43:32 -0700724 }
725 if (nsk == sk) {
Eric Dumazet079096f2015-10-02 11:43:32 -0700726 reqsk_put(req);
727 } else if (dccp_child_process(sk, nsk, skb)) {
728 dccp_v6_ctl_send_reset(sk, skb);
Eric Dumazet77166822016-02-18 05:39:18 -0800729 goto discard_and_relse;
Eric Dumazet079096f2015-10-02 11:43:32 -0700730 } else {
Eric Dumazet77166822016-02-18 05:39:18 -0800731 sock_put(sk);
Eric Dumazet079096f2015-10-02 11:43:32 -0700732 return 0;
733 }
734 }
Gerrit Renker6f4e5ff2006-11-10 17:43:06 -0200735 /*
736 * RFC 4340, sec. 9.2.1: Minimum Checksum Coverage
Arnaldo Carvalho de Melo8109b022006-12-10 16:01:18 -0200737 * o if MinCsCov = 0, only packets with CsCov = 0 are accepted
738 * o if MinCsCov > 0, also accept packets with CsCov >= MinCsCov
Gerrit Renker6f4e5ff2006-11-10 17:43:06 -0200739 */
740 min_cov = dccp_sk(sk)->dccps_pcrlen;
741 if (dh->dccph_cscov && (min_cov == 0 || dh->dccph_cscov < min_cov)) {
742 dccp_pr_debug("Packet CsCov %d does not satisfy MinCsCov %d\n",
743 dh->dccph_cscov, min_cov);
744 /* FIXME: send Data Dropped option (see also dccp_v4_rcv) */
745 goto discard_and_relse;
746 }
747
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800748 if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb))
749 goto discard_and_relse;
750
Eric Dumazetc3f24cf2016-11-02 17:14:41 -0700751 return __sk_receive_skb(sk, skb, 1, dh->dccph_doff * 4,
752 refcounted) ? -1 : 0;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800753
754no_dccp_socket:
755 if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb))
756 goto discard_it;
757 /*
758 * Step 2:
Arnaldo Carvalho de Melo8109b022006-12-10 16:01:18 -0200759 * If no socket ...
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800760 * Generate Reset(No Connection) unless P.type == Reset
761 * Drop packet and return
762 */
763 if (dh->dccph_type != DCCP_PKT_RESET) {
764 DCCP_SKB_CB(skb)->dccpd_reset_code =
765 DCCP_RESET_CODE_NO_CONNECTION;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800766 dccp_v6_ctl_send_reset(sk, skb);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800767 }
Gerrit Renkerd23c7102006-11-10 11:46:34 -0200768
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800769discard_it:
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800770 kfree_skb(skb);
771 return 0;
772
773discard_and_relse:
Eric Dumazet3b24d852016-04-01 08:52:17 -0700774 if (refcounted)
775 sock_put(sk);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800776 goto discard_it;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800777}
778
Gerrit Renker73c9e022006-11-10 13:01:31 -0200779static int dccp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
780 int addr_len)
781{
782 struct sockaddr_in6 *usin = (struct sockaddr_in6 *)uaddr;
783 struct inet_connection_sock *icsk = inet_csk(sk);
784 struct inet_sock *inet = inet_sk(sk);
785 struct ipv6_pinfo *np = inet6_sk(sk);
786 struct dccp_sock *dp = dccp_sk(sk);
Arnaud Ebalard20c59de2010-06-01 21:35:01 +0000787 struct in6_addr *saddr = NULL, *final_p, final;
Eric Dumazet45f6fad2015-11-29 19:37:57 -0800788 struct ipv6_txoptions *opt;
David S. Miller4c9483b2011-03-12 16:22:43 -0500789 struct flowi6 fl6;
Gerrit Renker73c9e022006-11-10 13:01:31 -0200790 struct dst_entry *dst;
791 int addr_type;
792 int err;
793
794 dp->dccps_role = DCCP_ROLE_CLIENT;
795
796 if (addr_len < SIN6_LEN_RFC2133)
797 return -EINVAL;
798
799 if (usin->sin6_family != AF_INET6)
800 return -EAFNOSUPPORT;
801
David S. Miller4c9483b2011-03-12 16:22:43 -0500802 memset(&fl6, 0, sizeof(fl6));
Gerrit Renker73c9e022006-11-10 13:01:31 -0200803
804 if (np->sndflow) {
David S. Miller4c9483b2011-03-12 16:22:43 -0500805 fl6.flowlabel = usin->sin6_flowinfo & IPV6_FLOWINFO_MASK;
806 IP6_ECN_flow_init(fl6.flowlabel);
807 if (fl6.flowlabel & IPV6_FLOWLABEL_MASK) {
Gerrit Renker73c9e022006-11-10 13:01:31 -0200808 struct ip6_flowlabel *flowlabel;
David S. Miller4c9483b2011-03-12 16:22:43 -0500809 flowlabel = fl6_sock_lookup(sk, fl6.flowlabel);
Gerrit Renker73c9e022006-11-10 13:01:31 -0200810 if (flowlabel == NULL)
811 return -EINVAL;
Gerrit Renker73c9e022006-11-10 13:01:31 -0200812 fl6_sock_release(flowlabel);
813 }
814 }
815 /*
816 * connect() to INADDR_ANY means loopback (BSD'ism).
817 */
818 if (ipv6_addr_any(&usin->sin6_addr))
819 usin->sin6_addr.s6_addr[15] = 1;
820
821 addr_type = ipv6_addr_type(&usin->sin6_addr);
822
823 if (addr_type & IPV6_ADDR_MULTICAST)
824 return -ENETUNREACH;
825
826 if (addr_type & IPV6_ADDR_LINKLOCAL) {
827 if (addr_len >= sizeof(struct sockaddr_in6) &&
828 usin->sin6_scope_id) {
829 /* If interface is set while binding, indices
830 * must coincide.
831 */
832 if (sk->sk_bound_dev_if &&
833 sk->sk_bound_dev_if != usin->sin6_scope_id)
834 return -EINVAL;
835
836 sk->sk_bound_dev_if = usin->sin6_scope_id;
837 }
838
839 /* Connect to link-local address requires an interface */
840 if (!sk->sk_bound_dev_if)
841 return -EINVAL;
842 }
843
Eric Dumazetefe42082013-10-03 15:42:29 -0700844 sk->sk_v6_daddr = usin->sin6_addr;
David S. Miller4c9483b2011-03-12 16:22:43 -0500845 np->flow_label = fl6.flowlabel;
Gerrit Renker73c9e022006-11-10 13:01:31 -0200846
847 /*
848 * DCCP over IPv4
849 */
850 if (addr_type == IPV6_ADDR_MAPPED) {
851 u32 exthdrlen = icsk->icsk_ext_hdr_len;
852 struct sockaddr_in sin;
853
854 SOCK_DEBUG(sk, "connect: ipv4 mapped\n");
855
856 if (__ipv6_only_sock(sk))
857 return -ENETUNREACH;
858
859 sin.sin_family = AF_INET;
860 sin.sin_port = usin->sin6_port;
861 sin.sin_addr.s_addr = usin->sin6_addr.s6_addr32[3];
862
863 icsk->icsk_af_ops = &dccp_ipv6_mapped;
864 sk->sk_backlog_rcv = dccp_v4_do_rcv;
865
866 err = dccp_v4_connect(sk, (struct sockaddr *)&sin, sizeof(sin));
867 if (err) {
868 icsk->icsk_ext_hdr_len = exthdrlen;
869 icsk->icsk_af_ops = &dccp_ipv6_af_ops;
870 sk->sk_backlog_rcv = dccp_v6_do_rcv;
871 goto failure;
Gerrit Renker73c9e022006-11-10 13:01:31 -0200872 }
Eric Dumazetd1e559d2015-03-18 14:05:35 -0700873 np->saddr = sk->sk_v6_rcv_saddr;
Gerrit Renker73c9e022006-11-10 13:01:31 -0200874 return err;
875 }
876
Eric Dumazetefe42082013-10-03 15:42:29 -0700877 if (!ipv6_addr_any(&sk->sk_v6_rcv_saddr))
878 saddr = &sk->sk_v6_rcv_saddr;
Gerrit Renker73c9e022006-11-10 13:01:31 -0200879
David S. Miller4c9483b2011-03-12 16:22:43 -0500880 fl6.flowi6_proto = IPPROTO_DCCP;
Eric Dumazetefe42082013-10-03 15:42:29 -0700881 fl6.daddr = sk->sk_v6_daddr;
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +0000882 fl6.saddr = saddr ? *saddr : np->saddr;
David S. Miller4c9483b2011-03-12 16:22:43 -0500883 fl6.flowi6_oif = sk->sk_bound_dev_if;
David S. Miller1958b852011-03-12 16:36:19 -0500884 fl6.fl6_dport = usin->sin6_port;
885 fl6.fl6_sport = inet->inet_sport;
David S. Miller4c9483b2011-03-12 16:22:43 -0500886 security_sk_classify_flow(sk, flowi6_to_flowi(&fl6));
Gerrit Renker73c9e022006-11-10 13:01:31 -0200887
Hannes Frederic Sowa1e1d04e2016-04-05 17:10:15 +0200888 opt = rcu_dereference_protected(np->opt, lockdep_sock_is_held(sk));
Eric Dumazet45f6fad2015-11-29 19:37:57 -0800889 final_p = fl6_update_dst(&fl6, opt, &final);
Gerrit Renker73c9e022006-11-10 13:01:31 -0200890
Steffen Klassert0e0d44a2013-08-28 08:04:14 +0200891 dst = ip6_dst_lookup_flow(sk, &fl6, final_p);
David S. Miller68d0c6d2011-03-01 13:19:07 -0800892 if (IS_ERR(dst)) {
893 err = PTR_ERR(dst);
Gerrit Renker73c9e022006-11-10 13:01:31 -0200894 goto failure;
David S. Miller14e50e52007-05-24 18:17:54 -0700895 }
Gerrit Renker73c9e022006-11-10 13:01:31 -0200896
897 if (saddr == NULL) {
David S. Miller4c9483b2011-03-12 16:22:43 -0500898 saddr = &fl6.saddr;
Eric Dumazetefe42082013-10-03 15:42:29 -0700899 sk->sk_v6_rcv_saddr = *saddr;
Gerrit Renker73c9e022006-11-10 13:01:31 -0200900 }
901
902 /* set the source address */
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +0000903 np->saddr = *saddr;
Eric Dumazetc720c7e2009-10-15 06:30:45 +0000904 inet->inet_rcv_saddr = LOOPBACK4_IPV6;
Gerrit Renker73c9e022006-11-10 13:01:31 -0200905
Eric Dumazet6bd4f352015-12-02 21:53:57 -0800906 ip6_dst_store(sk, dst, NULL, NULL);
Gerrit Renker73c9e022006-11-10 13:01:31 -0200907
908 icsk->icsk_ext_hdr_len = 0;
Eric Dumazet45f6fad2015-11-29 19:37:57 -0800909 if (opt)
910 icsk->icsk_ext_hdr_len = opt->opt_flen + opt->opt_nflen;
Gerrit Renker73c9e022006-11-10 13:01:31 -0200911
Eric Dumazetc720c7e2009-10-15 06:30:45 +0000912 inet->inet_dport = usin->sin6_port;
Gerrit Renker73c9e022006-11-10 13:01:31 -0200913
914 dccp_set_state(sk, DCCP_REQUESTING);
915 err = inet6_hash_connect(&dccp_death_row, sk);
916 if (err)
917 goto late_failure;
Gerrit Renkerd7f73652006-11-13 13:34:38 -0200918
919 dp->dccps_iss = secure_dccpv6_sequence_number(np->saddr.s6_addr32,
Eric Dumazetefe42082013-10-03 15:42:29 -0700920 sk->sk_v6_daddr.s6_addr32,
Eric Dumazetc720c7e2009-10-15 06:30:45 +0000921 inet->inet_sport,
922 inet->inet_dport);
Gerrit Renker73c9e022006-11-10 13:01:31 -0200923 err = dccp_connect(sk);
924 if (err)
925 goto late_failure;
926
927 return 0;
928
929late_failure:
930 dccp_set_state(sk, DCCP_CLOSED);
931 __sk_dst_reset(sk);
932failure:
Eric Dumazetc720c7e2009-10-15 06:30:45 +0000933 inet->inet_dport = 0;
Gerrit Renker73c9e022006-11-10 13:01:31 -0200934 sk->sk_route_caps = 0;
935 return err;
936}
937
Stephen Hemminger3b401a82009-09-01 19:25:04 +0000938static const struct inet_connection_sock_af_ops dccp_ipv6_af_ops = {
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -0800939 .queue_xmit = inet6_csk_xmit,
940 .send_check = dccp_v6_send_check,
941 .rebuild_header = inet6_sk_rebuild_header,
942 .conn_request = dccp_v6_conn_request,
943 .syn_recv_sock = dccp_v6_request_recv_sock,
944 .net_header_len = sizeof(struct ipv6hdr),
945 .setsockopt = ipv6_setsockopt,
946 .getsockopt = ipv6_getsockopt,
947 .addr2sockaddr = inet6_csk_addr2sockaddr,
948 .sockaddr_len = sizeof(struct sockaddr_in6),
Arnaldo Carvalho de Meloab1e0a12008-02-03 04:06:04 -0800949 .bind_conflict = inet6_csk_bind_conflict,
Dmitry Mishin3fdadf72006-03-20 22:45:21 -0800950#ifdef CONFIG_COMPAT
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -0800951 .compat_setsockopt = compat_ipv6_setsockopt,
952 .compat_getsockopt = compat_ipv6_getsockopt,
Dmitry Mishin3fdadf72006-03-20 22:45:21 -0800953#endif
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800954};
955
956/*
957 * DCCP over IPv4 via INET6 API
958 */
Stephen Hemminger3b401a82009-09-01 19:25:04 +0000959static const struct inet_connection_sock_af_ops dccp_ipv6_mapped = {
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -0800960 .queue_xmit = ip_queue_xmit,
961 .send_check = dccp_v4_send_check,
962 .rebuild_header = inet_sk_rebuild_header,
963 .conn_request = dccp_v6_conn_request,
964 .syn_recv_sock = dccp_v6_request_recv_sock,
965 .net_header_len = sizeof(struct iphdr),
966 .setsockopt = ipv6_setsockopt,
967 .getsockopt = ipv6_getsockopt,
968 .addr2sockaddr = inet6_csk_addr2sockaddr,
969 .sockaddr_len = sizeof(struct sockaddr_in6),
Eric Dumazet990ff4d2016-11-03 08:59:46 -0700970 .bind_conflict = inet6_csk_bind_conflict,
Dmitry Mishin3fdadf72006-03-20 22:45:21 -0800971#ifdef CONFIG_COMPAT
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -0800972 .compat_setsockopt = compat_ipv6_setsockopt,
973 .compat_getsockopt = compat_ipv6_getsockopt,
Dmitry Mishin3fdadf72006-03-20 22:45:21 -0800974#endif
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800975};
976
977/* NOTE: A lot of things set to zero explicitly by call to
978 * sk_alloc() so need not be done here.
979 */
980static int dccp_v6_init_sock(struct sock *sk)
981{
Arnaldo Carvalho de Melo72478872006-03-20 22:00:37 -0800982 static __u8 dccp_v6_ctl_sock_initialized;
983 int err = dccp_init_sock(sk, dccp_v6_ctl_sock_initialized);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800984
Arnaldo Carvalho de Melo72478872006-03-20 22:00:37 -0800985 if (err == 0) {
986 if (unlikely(!dccp_v6_ctl_sock_initialized))
987 dccp_v6_ctl_sock_initialized = 1;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800988 inet_csk(sk)->icsk_af_ops = &dccp_ipv6_af_ops;
Arnaldo Carvalho de Melo72478872006-03-20 22:00:37 -0800989 }
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800990
991 return err;
992}
993
Brian Haley7d06b2e2008-06-14 17:04:49 -0700994static void dccp_v6_destroy_sock(struct sock *sk)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800995{
Arnaldo Carvalho de Melo3e0fadc2006-03-20 21:23:15 -0800996 dccp_destroy_sock(sk);
Brian Haley7d06b2e2008-06-14 17:04:49 -0700997 inet6_destroy_sock(sk);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800998}
999
Gerrit Renker73c9e022006-11-10 13:01:31 -02001000static struct timewait_sock_ops dccp6_timewait_sock_ops = {
1001 .twsk_obj_size = sizeof(struct dccp6_timewait_sock),
1002};
1003
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001004static struct proto dccp_v6_prot = {
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001005 .name = "DCCPv6",
1006 .owner = THIS_MODULE,
1007 .close = dccp_close,
1008 .connect = dccp_v6_connect,
1009 .disconnect = dccp_disconnect,
1010 .ioctl = dccp_ioctl,
1011 .init = dccp_v6_init_sock,
1012 .setsockopt = dccp_setsockopt,
1013 .getsockopt = dccp_getsockopt,
1014 .sendmsg = dccp_sendmsg,
1015 .recvmsg = dccp_recvmsg,
1016 .backlog_rcv = dccp_v6_do_rcv,
Craig Gallek496611d2016-02-10 11:50:36 -05001017 .hash = inet6_hash,
Arnaldo Carvalho de Meloab1e0a12008-02-03 04:06:04 -08001018 .unhash = inet_unhash,
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001019 .accept = inet_csk_accept,
Arnaldo Carvalho de Meloab1e0a12008-02-03 04:06:04 -08001020 .get_port = inet_csk_get_port,
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001021 .shutdown = dccp_shutdown,
1022 .destroy = dccp_v6_destroy_sock,
1023 .orphan_count = &dccp_orphan_count,
1024 .max_header = MAX_DCCP_HEADER,
1025 .obj_size = sizeof(struct dccp6_sock),
Eric Dumazet3ab5aee2008-11-16 19:40:17 -08001026 .slab_flags = SLAB_DESTROY_BY_RCU,
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001027 .rsk_prot = &dccp6_request_sock_ops,
1028 .twsk_prot = &dccp6_timewait_sock_ops,
Pavel Emelyanov39d8cda2008-03-22 16:50:58 -07001029 .h.hashinfo = &dccp_hashinfo,
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001030#ifdef CONFIG_COMPAT
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001031 .compat_setsockopt = compat_dccp_setsockopt,
1032 .compat_getsockopt = compat_dccp_getsockopt,
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001033#endif
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001034};
1035
Alexey Dobriyan41135cc2009-09-14 12:22:28 +00001036static const struct inet6_protocol dccp_v6_protocol = {
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -08001037 .handler = dccp_v6_rcv,
1038 .err_handler = dccp_v6_err,
1039 .flags = INET6_PROTO_NOPOLICY | INET6_PROTO_FINAL,
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001040};
1041
Alexey Dobriyan5708e862009-09-14 12:23:23 +00001042static const struct proto_ops inet6_dccp_ops = {
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001043 .family = PF_INET6,
1044 .owner = THIS_MODULE,
1045 .release = inet6_release,
1046 .bind = inet6_bind,
1047 .connect = inet_stream_connect,
1048 .socketpair = sock_no_socketpair,
1049 .accept = inet_accept,
1050 .getname = inet6_getname,
1051 .poll = dccp_poll,
1052 .ioctl = inet6_ioctl,
1053 .listen = inet_dccp_listen,
1054 .shutdown = inet_shutdown,
1055 .setsockopt = sock_common_setsockopt,
1056 .getsockopt = sock_common_getsockopt,
1057 .sendmsg = inet_sendmsg,
1058 .recvmsg = sock_common_recvmsg,
1059 .mmap = sock_no_mmap,
1060 .sendpage = sock_no_sendpage,
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001061#ifdef CONFIG_COMPAT
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001062 .compat_setsockopt = compat_sock_common_setsockopt,
1063 .compat_getsockopt = compat_sock_common_getsockopt,
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001064#endif
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001065};
1066
1067static struct inet_protosw dccp_v6_protosw = {
1068 .type = SOCK_DCCP,
1069 .protocol = IPPROTO_DCCP,
1070 .prot = &dccp_v6_prot,
1071 .ops = &inet6_dccp_ops,
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -08001072 .flags = INET_PROTOSW_ICSK,
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001073};
1074
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00001075static int __net_init dccp_v6_init_net(struct net *net)
Pavel Emelyanov8231bd22008-04-13 22:32:02 -07001076{
Gerrit Renkerd14a0eb2010-03-14 20:13:19 +00001077 if (dccp_hashinfo.bhash == NULL)
1078 return -ESOCKTNOSUPPORT;
Pavel Emelyanov334527d2008-04-13 22:32:45 -07001079
Gerrit Renkerd14a0eb2010-03-14 20:13:19 +00001080 return inet_ctl_sock_create(&net->dccp.v6_ctl_sk, PF_INET6,
1081 SOCK_DCCP, IPPROTO_DCCP, net);
Pavel Emelyanov8231bd22008-04-13 22:32:02 -07001082}
1083
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00001084static void __net_exit dccp_v6_exit_net(struct net *net)
Pavel Emelyanov8231bd22008-04-13 22:32:02 -07001085{
Pavel Emelyanov334527d2008-04-13 22:32:45 -07001086 inet_ctl_sock_destroy(net->dccp.v6_ctl_sk);
Pavel Emelyanov8231bd22008-04-13 22:32:02 -07001087}
1088
1089static struct pernet_operations dccp_v6_ops = {
1090 .init = dccp_v6_init_net,
1091 .exit = dccp_v6_exit_net,
1092};
1093
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001094static int __init dccp_v6_init(void)
1095{
1096 int err = proto_register(&dccp_v6_prot, 1);
1097
1098 if (err != 0)
1099 goto out;
1100
1101 err = inet6_add_protocol(&dccp_v6_protocol, IPPROTO_DCCP);
1102 if (err != 0)
1103 goto out_unregister_proto;
1104
1105 inet6_register_protosw(&dccp_v6_protosw);
Arnaldo Carvalho de Melo72478872006-03-20 22:00:37 -08001106
Pavel Emelyanov8231bd22008-04-13 22:32:02 -07001107 err = register_pernet_subsys(&dccp_v6_ops);
1108 if (err != 0)
1109 goto out_destroy_ctl_sock;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001110out:
1111 return err;
Pavel Emelyanov8231bd22008-04-13 22:32:02 -07001112
1113out_destroy_ctl_sock:
Arnaldo Carvalho de Melo72478872006-03-20 22:00:37 -08001114 inet6_del_protocol(&dccp_v6_protocol, IPPROTO_DCCP);
1115 inet6_unregister_protosw(&dccp_v6_protosw);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001116out_unregister_proto:
1117 proto_unregister(&dccp_v6_prot);
1118 goto out;
1119}
1120
1121static void __exit dccp_v6_exit(void)
1122{
Pavel Emelyanov8231bd22008-04-13 22:32:02 -07001123 unregister_pernet_subsys(&dccp_v6_ops);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001124 inet6_del_protocol(&dccp_v6_protocol, IPPROTO_DCCP);
1125 inet6_unregister_protosw(&dccp_v6_protosw);
1126 proto_unregister(&dccp_v6_prot);
1127}
1128
1129module_init(dccp_v6_init);
1130module_exit(dccp_v6_exit);
1131
1132/*
1133 * __stringify doesn't likes enums, so use SOCK_DCCP (6) and IPPROTO_DCCP (33)
1134 * values directly, Also cover the case where the protocol is not specified,
1135 * i.e. net-pf-PF_INET6-proto-0-type-SOCK_DCCP
1136 */
Jean Delvare7131c6c2007-10-21 16:45:03 -07001137MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_INET6, 33, 6);
1138MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_INET6, 0, 6);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001139MODULE_LICENSE("GPL");
1140MODULE_AUTHOR("Arnaldo Carvalho de Melo <acme@mandriva.com>");
1141MODULE_DESCRIPTION("DCCPv6 - Datagram Congestion Controlled Protocol");