blob: 840f14aaa01635e0f6fb62232b67814736c84b5d [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 Maxwell45caeaa2017-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 Maxwell45caeaa2017-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 Neira92e55f42017-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 Neira92e55f42017-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
Eric Dumazet5ea8ea22016-10-26 09:27:57 -0700331 if (sk_acceptq_is_full(sk))
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800332 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);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800383 return 0;
384
385drop_and_free:
386 reqsk_free(req);
387drop:
Eric Dumazetaa62d762016-04-27 16:44:28 -0700388 __DCCP_INC_STATS(DCCP_MIB_ATTEMPTFAILS);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800389 return -1;
390}
391
Eric Dumazet0c271712015-09-29 07:42:48 -0700392static struct sock *dccp_v6_request_recv_sock(const struct sock *sk,
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800393 struct sk_buff *skb,
394 struct request_sock *req,
Eric Dumazet5e0724d2015-10-22 08:20:46 -0700395 struct dst_entry *dst,
396 struct request_sock *req_unhash,
397 bool *own_req)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800398{
Eric Dumazet634fb9792013-10-09 15:21:29 -0700399 struct inet_request_sock *ireq = inet_rsk(req);
Eric Dumazet0c271712015-09-29 07:42:48 -0700400 struct ipv6_pinfo *newnp;
401 const struct ipv6_pinfo *np = inet6_sk(sk);
Eric Dumazet45f6fad2015-11-29 19:37:57 -0800402 struct ipv6_txoptions *opt;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800403 struct inet_sock *newinet;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800404 struct dccp6_sock *newdp6;
405 struct sock *newsk;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800406
407 if (skb->protocol == htons(ETH_P_IP)) {
408 /*
409 * v6 mapped
410 */
Eric Dumazet5e0724d2015-10-22 08:20:46 -0700411 newsk = dccp_v4_request_recv_sock(sk, skb, req, dst,
412 req_unhash, own_req);
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800413 if (newsk == NULL)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800414 return NULL;
415
416 newdp6 = (struct dccp6_sock *)newsk;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800417 newinet = inet_sk(newsk);
418 newinet->pinet6 = &newdp6->inet6;
419 newnp = inet6_sk(newsk);
420
421 memcpy(newnp, np, sizeof(struct ipv6_pinfo));
422
Eric Dumazetd1e559d2015-03-18 14:05:35 -0700423 newnp->saddr = newsk->sk_v6_rcv_saddr;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800424
425 inet_csk(newsk)->icsk_af_ops = &dccp_ipv6_mapped;
426 newsk->sk_backlog_rcv = dccp_v4_do_rcv;
427 newnp->pktoptions = NULL;
428 newnp->opt = NULL;
429 newnp->mcast_oif = inet6_iif(skb);
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700430 newnp->mcast_hops = ipv6_hdr(skb)->hop_limit;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800431
432 /*
433 * No need to charge this sock to the relevant IPv6 refcnt debug socks count
434 * here, dccp_create_openreq_child now does this for us, see the comment in
435 * that function for the gory details. -acme
436 */
437
438 /* It is tricky place. Until this moment IPv4 tcp
439 worked with IPv6 icsk.icsk_af_ops.
440 Sync it now.
441 */
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -0800442 dccp_sync_mss(newsk, inet_csk(newsk)->icsk_pmtu_cookie);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800443
444 return newsk;
445 }
446
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800447
448 if (sk_acceptq_is_full(sk))
449 goto out_overflow;
450
Eric Dumazetf76b33c2015-09-29 07:42:42 -0700451 if (!dst) {
David S. Miller4c9483b2011-03-12 16:22:43 -0500452 struct flowi6 fl6;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800453
Eric Dumazetf76b33c2015-09-29 07:42:42 -0700454 dst = inet6_csk_route_req(sk, &fl6, req, IPPROTO_DCCP);
455 if (!dst)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800456 goto out;
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800457 }
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800458
459 newsk = dccp_create_openreq_child(sk, req, skb);
460 if (newsk == NULL)
Balazs Scheidler093d2822010-10-21 13:06:43 +0200461 goto out_nonewsk;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800462
463 /*
464 * No need to charge this sock to the relevant IPv6 refcnt debug socks
465 * count here, dccp_create_openreq_child now does this for us, see the
466 * comment in that function for the gory details. -acme
467 */
468
Eric Dumazet6bd4f352015-12-02 21:53:57 -0800469 ip6_dst_store(newsk, dst, NULL, NULL);
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800470 newsk->sk_route_caps = dst->dev->features & ~(NETIF_F_IP_CSUM |
471 NETIF_F_TSO);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800472 newdp6 = (struct dccp6_sock *)newsk;
473 newinet = inet_sk(newsk);
474 newinet->pinet6 = &newdp6->inet6;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800475 newnp = inet6_sk(newsk);
476
477 memcpy(newnp, np, sizeof(struct ipv6_pinfo));
478
Eric Dumazet634fb9792013-10-09 15:21:29 -0700479 newsk->sk_v6_daddr = ireq->ir_v6_rmt_addr;
480 newnp->saddr = ireq->ir_v6_loc_addr;
481 newsk->sk_v6_rcv_saddr = ireq->ir_v6_loc_addr;
482 newsk->sk_bound_dev_if = ireq->ir_iif;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800483
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800484 /* Now IPv6 options...
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800485
486 First: no IPv4 options.
487 */
Eric Dumazetf6d8bd02011-04-21 09:45:37 +0000488 newinet->inet_opt = NULL;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800489
490 /* Clone RX bits */
491 newnp->rxopt.all = np->rxopt.all;
492
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800493 newnp->pktoptions = NULL;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800494 newnp->opt = NULL;
495 newnp->mcast_oif = inet6_iif(skb);
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700496 newnp->mcast_hops = ipv6_hdr(skb)->hop_limit;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800497
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800498 /*
499 * Clone native IPv6 options from listening socket (if any)
500 *
501 * Yes, keeping reference count would be much more clever, but we make
502 * one more one thing there: reattach optmem to newsk.
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800503 */
Huw Davies56ac42b2016-06-27 15:05:28 -0400504 opt = ireq->ipv6_opt;
505 if (!opt)
506 opt = rcu_dereference(np->opt);
Eric Dumazet45f6fad2015-11-29 19:37:57 -0800507 if (opt) {
508 opt = ipv6_dup_options(newsk, opt);
509 RCU_INIT_POINTER(newnp->opt, opt);
510 }
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -0800511 inet_csk(newsk)->icsk_ext_hdr_len = 0;
Eric Dumazet45f6fad2015-11-29 19:37:57 -0800512 if (opt)
513 inet_csk(newsk)->icsk_ext_hdr_len = opt->opt_nflen +
514 opt->opt_flen;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800515
516 dccp_sync_mss(newsk, dst_mtu(dst));
517
Eric Dumazetc720c7e2009-10-15 06:30:45 +0000518 newinet->inet_daddr = newinet->inet_saddr = LOOPBACK4_IPV6;
519 newinet->inet_rcv_saddr = LOOPBACK4_IPV6;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800520
Balazs Scheidler093d2822010-10-21 13:06:43 +0200521 if (__inet_inherit_port(sk, newsk) < 0) {
Christoph Paasche337e242012-12-14 04:07:58 +0000522 inet_csk_prepare_forced_close(newsk);
523 dccp_done(newsk);
Balazs Scheidler093d2822010-10-21 13:06:43 +0200524 goto out;
525 }
Eric Dumazet5e0724d2015-10-22 08:20:46 -0700526 *own_req = inet_ehash_nolisten(newsk, req_to_sk(req_unhash));
Eric Dumazetce105002015-10-30 09:46:12 -0700527 /* Clone pktoptions received with SYN, if we own the req */
528 if (*own_req && ireq->pktopts) {
529 newnp->pktoptions = skb_clone(ireq->pktopts, GFP_ATOMIC);
530 consume_skb(ireq->pktopts);
531 ireq->pktopts = NULL;
532 if (newnp->pktoptions)
533 skb_set_owner_r(newnp->pktoptions, newsk);
534 }
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800535
536 return newsk;
537
538out_overflow:
Eric Dumazet02a1d6e2016-04-27 16:44:39 -0700539 __NET_INC_STATS(sock_net(sk), LINUX_MIB_LISTENOVERFLOWS);
Balazs Scheidler093d2822010-10-21 13:06:43 +0200540out_nonewsk:
541 dst_release(dst);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800542out:
Eric Dumazet02a1d6e2016-04-27 16:44:39 -0700543 __NET_INC_STATS(sock_net(sk), LINUX_MIB_LISTENDROPS);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800544 return NULL;
545}
546
547/* The socket must have it's spinlock held when we get
548 * here.
549 *
550 * We have a potential double-lock case here, so even when
551 * doing backlog processing we use the BH locking scheme.
552 * This is because we cannot sleep with the original spinlock
553 * held.
554 */
555static int dccp_v6_do_rcv(struct sock *sk, struct sk_buff *skb)
556{
557 struct ipv6_pinfo *np = inet6_sk(sk);
558 struct sk_buff *opt_skb = NULL;
559
560 /* Imagine: socket is IPv6. IPv4 packet arrives,
561 goes to IPv4 receive handler and backlogged.
562 From backlog it always goes here. Kerboom...
563 Fortunately, dccp_rcv_established and rcv_established
564 handle them correctly, but it is not case with
565 dccp_v6_hnd_req and dccp_v6_ctl_send_reset(). --ANK
566 */
567
568 if (skb->protocol == htons(ETH_P_IP))
569 return dccp_v4_do_rcv(sk, skb);
570
Dmitry Mishinfda9ef52006-08-31 15:28:39 -0700571 if (sk_filter(sk, skb))
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800572 goto discard;
573
574 /*
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800575 * socket locking is here for SMP purposes as backlog rcv is currently
576 * called with bh processing disabled.
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800577 */
578
579 /* Do Stevens' IPV6_PKTOPTIONS.
580
581 Yes, guys, it is the only place in our code, where we
582 may make it not affecting IPv4.
583 The rest of code is protocol independent,
584 and I do not like idea to uglify IPv4.
585
586 Actually, all the idea behind IPV6_PKTOPTIONS
587 looks not very well thought. For now we latch
588 options, received in the last packet, enqueued
589 by tcp. Feel free to propose better solution.
YOSHIFUJI Hideakic9eaf172007-02-09 23:24:38 +0900590 --ANK (980728)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800591 */
592 if (np->rxopt.all)
Gerrit Renker89e7e572006-11-10 11:13:33 -0200593 /*
594 * FIXME: Add handling of IPV6_PKTOPTIONS skb. See the comments below
595 * (wrt ipv6_pktopions) and net/ipv6/tcp_ipv6.c for an example.
596 */
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800597 opt_skb = skb_clone(skb, GFP_ATOMIC);
598
599 if (sk->sk_state == DCCP_OPEN) { /* Fast path */
600 if (dccp_rcv_established(sk, skb, dccp_hdr(skb), skb->len))
601 goto reset;
David S. Millerfd169f12006-10-20 19:44:17 -0700602 if (opt_skb) {
Gerrit Renker89e7e572006-11-10 11:13:33 -0200603 /* XXX This is where we would goto ipv6_pktoptions. */
David S. Millerfd169f12006-10-20 19:44:17 -0700604 __kfree_skb(opt_skb);
605 }
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800606 return 0;
607 }
608
Gerrit Renkerd83ca5a2006-11-10 16:29:14 -0200609 /*
610 * Step 3: Process LISTEN state
611 * If S.state == LISTEN,
612 * If P.type == Request or P contains a valid Init Cookie option,
613 * (* Must scan the packet's options to check for Init
614 * Cookies. Only Init Cookies are processed here,
615 * however; other options are processed in Step 8. This
616 * scan need only be performed if the endpoint uses Init
617 * Cookies *)
618 * (* Generate a new socket and switch to that socket *)
619 * Set S := new socket for this port pair
620 * S.state = RESPOND
621 * Choose S.ISS (initial seqno) or set from Init Cookies
622 * Initialize S.GAR := S.ISS
623 * Set S.ISR, S.GSR, S.SWL, S.SWH from packet or Init Cookies
624 * Continue with S.state == RESPOND
625 * (* A Response packet will be generated in Step 11 *)
626 * Otherwise,
627 * Generate Reset(No Connection) unless P.type == Reset
628 * Drop packet and return
629 *
630 * NOTE: the check for the packet types is done in
631 * dccp_rcv_state_process
632 */
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800633
634 if (dccp_rcv_state_process(sk, skb, dccp_hdr(skb), skb->len))
635 goto reset;
David S. Millerfd169f12006-10-20 19:44:17 -0700636 if (opt_skb) {
Gerrit Renker89e7e572006-11-10 11:13:33 -0200637 /* XXX This is where we would goto ipv6_pktoptions. */
David S. Millerfd169f12006-10-20 19:44:17 -0700638 __kfree_skb(opt_skb);
639 }
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800640 return 0;
641
642reset:
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800643 dccp_v6_ctl_send_reset(sk, skb);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800644discard:
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800645 if (opt_skb != NULL)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800646 __kfree_skb(opt_skb);
647 kfree_skb(skb);
648 return 0;
649}
650
Herbert Xue5bbef22007-10-15 12:50:28 -0700651static int dccp_v6_rcv(struct sk_buff *skb)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800652{
653 const struct dccp_hdr *dh;
Eric Dumazet3b24d852016-04-01 08:52:17 -0700654 bool refcounted;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800655 struct sock *sk;
Gerrit Renker6f4e5ff2006-11-10 17:43:06 -0200656 int min_cov;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800657
Gerrit Renker6f4e5ff2006-11-10 17:43:06 -0200658 /* Step 1: Check header basics */
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800659
660 if (dccp_invalid_packet(skb))
661 goto discard_it;
662
Gerrit Renker6f4e5ff2006-11-10 17:43:06 -0200663 /* Step 1: If header checksum is incorrect, drop packet and return. */
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700664 if (dccp_v6_csum_finish(skb, &ipv6_hdr(skb)->saddr,
665 &ipv6_hdr(skb)->daddr)) {
Gerrit Renker59348b12006-11-20 18:39:23 -0200666 DCCP_WARN("dropped packet with invalid checksum\n");
Gerrit Renker6f4e5ff2006-11-10 17:43:06 -0200667 goto discard_it;
668 }
669
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800670 dh = dccp_hdr(skb);
671
Gerrit Renkerfde20102007-10-24 10:12:09 -0200672 DCCP_SKB_CB(skb)->dccpd_seq = dccp_hdr_seq(dh);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800673 DCCP_SKB_CB(skb)->dccpd_type = dh->dccph_type;
674
675 if (dccp_packet_without_ack(skb))
676 DCCP_SKB_CB(skb)->dccpd_ack_seq = DCCP_PKT_WITHOUT_ACK_SEQ;
677 else
678 DCCP_SKB_CB(skb)->dccpd_ack_seq = dccp_hdr_ack_seq(skb);
679
Eric Dumazet4bdc3d62015-10-13 17:12:54 -0700680lookup:
Craig Galleka5836362016-02-10 11:50:38 -0500681 sk = __inet6_lookup_skb(&dccp_hashinfo, skb, __dccp_hdr_len(dh),
Eric Dumazet870c3152014-10-17 09:17:20 -0700682 dh->dccph_sport, dh->dccph_dport,
Eric Dumazet3b24d852016-04-01 08:52:17 -0700683 inet6_iif(skb), &refcounted);
Eric Dumazet4bdc3d62015-10-13 17:12:54 -0700684 if (!sk) {
Gerrit Renkerd23c7102006-11-10 11:46:34 -0200685 dccp_pr_debug("failed to look up flow ID in table and "
686 "get corresponding socket\n");
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800687 goto no_dccp_socket;
Gerrit Renkerd23c7102006-11-10 11:46:34 -0200688 }
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800689
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800690 /*
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800691 * Step 2:
Arnaldo Carvalho de Melo8109b022006-12-10 16:01:18 -0200692 * ... or S.state == TIMEWAIT,
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800693 * Generate Reset(No Connection) unless P.type == Reset
694 * Drop packet and return
695 */
Gerrit Renkerd23c7102006-11-10 11:46:34 -0200696 if (sk->sk_state == DCCP_TIME_WAIT) {
697 dccp_pr_debug("sk->sk_state == DCCP_TIME_WAIT: do_time_wait\n");
698 inet_twsk_put(inet_twsk(sk));
699 goto no_dccp_socket;
700 }
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800701
Eric Dumazet079096f2015-10-02 11:43:32 -0700702 if (sk->sk_state == DCCP_NEW_SYN_RECV) {
703 struct request_sock *req = inet_reqsk(sk);
Eric Dumazet77166822016-02-18 05:39:18 -0800704 struct sock *nsk;
Eric Dumazet079096f2015-10-02 11:43:32 -0700705
706 sk = req->rsk_listener;
Eric Dumazet77166822016-02-18 05:39:18 -0800707 if (unlikely(sk->sk_state != DCCP_LISTEN)) {
Eric Dumazetf03f2e12015-10-14 11:16:27 -0700708 inet_csk_reqsk_queue_drop_and_put(sk, req);
Eric Dumazet4bdc3d62015-10-13 17:12:54 -0700709 goto lookup;
710 }
Eric Dumazet77166822016-02-18 05:39:18 -0800711 sock_hold(sk);
Eric Dumazet3b24d852016-04-01 08:52:17 -0700712 refcounted = true;
Eric Dumazet77166822016-02-18 05:39:18 -0800713 nsk = dccp_check_req(sk, skb, req);
Eric Dumazet079096f2015-10-02 11:43:32 -0700714 if (!nsk) {
715 reqsk_put(req);
Eric Dumazet77166822016-02-18 05:39:18 -0800716 goto discard_and_relse;
Eric Dumazet079096f2015-10-02 11:43:32 -0700717 }
718 if (nsk == sk) {
Eric Dumazet079096f2015-10-02 11:43:32 -0700719 reqsk_put(req);
720 } else if (dccp_child_process(sk, nsk, skb)) {
721 dccp_v6_ctl_send_reset(sk, skb);
Eric Dumazet77166822016-02-18 05:39:18 -0800722 goto discard_and_relse;
Eric Dumazet079096f2015-10-02 11:43:32 -0700723 } else {
Eric Dumazet77166822016-02-18 05:39:18 -0800724 sock_put(sk);
Eric Dumazet079096f2015-10-02 11:43:32 -0700725 return 0;
726 }
727 }
Gerrit Renker6f4e5ff2006-11-10 17:43:06 -0200728 /*
729 * RFC 4340, sec. 9.2.1: Minimum Checksum Coverage
Arnaldo Carvalho de Melo8109b022006-12-10 16:01:18 -0200730 * o if MinCsCov = 0, only packets with CsCov = 0 are accepted
731 * o if MinCsCov > 0, also accept packets with CsCov >= MinCsCov
Gerrit Renker6f4e5ff2006-11-10 17:43:06 -0200732 */
733 min_cov = dccp_sk(sk)->dccps_pcrlen;
734 if (dh->dccph_cscov && (min_cov == 0 || dh->dccph_cscov < min_cov)) {
735 dccp_pr_debug("Packet CsCov %d does not satisfy MinCsCov %d\n",
736 dh->dccph_cscov, min_cov);
737 /* FIXME: send Data Dropped option (see also dccp_v4_rcv) */
738 goto discard_and_relse;
739 }
740
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800741 if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb))
742 goto discard_and_relse;
743
Eric Dumazetc3f24cf2016-11-02 17:14:41 -0700744 return __sk_receive_skb(sk, skb, 1, dh->dccph_doff * 4,
745 refcounted) ? -1 : 0;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800746
747no_dccp_socket:
748 if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb))
749 goto discard_it;
750 /*
751 * Step 2:
Arnaldo Carvalho de Melo8109b022006-12-10 16:01:18 -0200752 * If no socket ...
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800753 * Generate Reset(No Connection) unless P.type == Reset
754 * Drop packet and return
755 */
756 if (dh->dccph_type != DCCP_PKT_RESET) {
757 DCCP_SKB_CB(skb)->dccpd_reset_code =
758 DCCP_RESET_CODE_NO_CONNECTION;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800759 dccp_v6_ctl_send_reset(sk, skb);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800760 }
Gerrit Renkerd23c7102006-11-10 11:46:34 -0200761
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800762discard_it:
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800763 kfree_skb(skb);
764 return 0;
765
766discard_and_relse:
Eric Dumazet3b24d852016-04-01 08:52:17 -0700767 if (refcounted)
768 sock_put(sk);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800769 goto discard_it;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800770}
771
Gerrit Renker73c9e022006-11-10 13:01:31 -0200772static int dccp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
773 int addr_len)
774{
775 struct sockaddr_in6 *usin = (struct sockaddr_in6 *)uaddr;
776 struct inet_connection_sock *icsk = inet_csk(sk);
777 struct inet_sock *inet = inet_sk(sk);
778 struct ipv6_pinfo *np = inet6_sk(sk);
779 struct dccp_sock *dp = dccp_sk(sk);
Arnaud Ebalard20c59de2010-06-01 21:35:01 +0000780 struct in6_addr *saddr = NULL, *final_p, final;
Eric Dumazet45f6fad2015-11-29 19:37:57 -0800781 struct ipv6_txoptions *opt;
David S. Miller4c9483b2011-03-12 16:22:43 -0500782 struct flowi6 fl6;
Gerrit Renker73c9e022006-11-10 13:01:31 -0200783 struct dst_entry *dst;
784 int addr_type;
785 int err;
786
787 dp->dccps_role = DCCP_ROLE_CLIENT;
788
789 if (addr_len < SIN6_LEN_RFC2133)
790 return -EINVAL;
791
792 if (usin->sin6_family != AF_INET6)
793 return -EAFNOSUPPORT;
794
David S. Miller4c9483b2011-03-12 16:22:43 -0500795 memset(&fl6, 0, sizeof(fl6));
Gerrit Renker73c9e022006-11-10 13:01:31 -0200796
797 if (np->sndflow) {
David S. Miller4c9483b2011-03-12 16:22:43 -0500798 fl6.flowlabel = usin->sin6_flowinfo & IPV6_FLOWINFO_MASK;
799 IP6_ECN_flow_init(fl6.flowlabel);
800 if (fl6.flowlabel & IPV6_FLOWLABEL_MASK) {
Gerrit Renker73c9e022006-11-10 13:01:31 -0200801 struct ip6_flowlabel *flowlabel;
David S. Miller4c9483b2011-03-12 16:22:43 -0500802 flowlabel = fl6_sock_lookup(sk, fl6.flowlabel);
Gerrit Renker73c9e022006-11-10 13:01:31 -0200803 if (flowlabel == NULL)
804 return -EINVAL;
Gerrit Renker73c9e022006-11-10 13:01:31 -0200805 fl6_sock_release(flowlabel);
806 }
807 }
808 /*
809 * connect() to INADDR_ANY means loopback (BSD'ism).
810 */
811 if (ipv6_addr_any(&usin->sin6_addr))
812 usin->sin6_addr.s6_addr[15] = 1;
813
814 addr_type = ipv6_addr_type(&usin->sin6_addr);
815
816 if (addr_type & IPV6_ADDR_MULTICAST)
817 return -ENETUNREACH;
818
819 if (addr_type & IPV6_ADDR_LINKLOCAL) {
820 if (addr_len >= sizeof(struct sockaddr_in6) &&
821 usin->sin6_scope_id) {
822 /* If interface is set while binding, indices
823 * must coincide.
824 */
825 if (sk->sk_bound_dev_if &&
826 sk->sk_bound_dev_if != usin->sin6_scope_id)
827 return -EINVAL;
828
829 sk->sk_bound_dev_if = usin->sin6_scope_id;
830 }
831
832 /* Connect to link-local address requires an interface */
833 if (!sk->sk_bound_dev_if)
834 return -EINVAL;
835 }
836
Eric Dumazetefe42082013-10-03 15:42:29 -0700837 sk->sk_v6_daddr = usin->sin6_addr;
David S. Miller4c9483b2011-03-12 16:22:43 -0500838 np->flow_label = fl6.flowlabel;
Gerrit Renker73c9e022006-11-10 13:01:31 -0200839
840 /*
841 * DCCP over IPv4
842 */
843 if (addr_type == IPV6_ADDR_MAPPED) {
844 u32 exthdrlen = icsk->icsk_ext_hdr_len;
845 struct sockaddr_in sin;
846
847 SOCK_DEBUG(sk, "connect: ipv4 mapped\n");
848
849 if (__ipv6_only_sock(sk))
850 return -ENETUNREACH;
851
852 sin.sin_family = AF_INET;
853 sin.sin_port = usin->sin6_port;
854 sin.sin_addr.s_addr = usin->sin6_addr.s6_addr32[3];
855
856 icsk->icsk_af_ops = &dccp_ipv6_mapped;
857 sk->sk_backlog_rcv = dccp_v4_do_rcv;
858
859 err = dccp_v4_connect(sk, (struct sockaddr *)&sin, sizeof(sin));
860 if (err) {
861 icsk->icsk_ext_hdr_len = exthdrlen;
862 icsk->icsk_af_ops = &dccp_ipv6_af_ops;
863 sk->sk_backlog_rcv = dccp_v6_do_rcv;
864 goto failure;
Gerrit Renker73c9e022006-11-10 13:01:31 -0200865 }
Eric Dumazetd1e559d2015-03-18 14:05:35 -0700866 np->saddr = sk->sk_v6_rcv_saddr;
Gerrit Renker73c9e022006-11-10 13:01:31 -0200867 return err;
868 }
869
Eric Dumazetefe42082013-10-03 15:42:29 -0700870 if (!ipv6_addr_any(&sk->sk_v6_rcv_saddr))
871 saddr = &sk->sk_v6_rcv_saddr;
Gerrit Renker73c9e022006-11-10 13:01:31 -0200872
David S. Miller4c9483b2011-03-12 16:22:43 -0500873 fl6.flowi6_proto = IPPROTO_DCCP;
Eric Dumazetefe42082013-10-03 15:42:29 -0700874 fl6.daddr = sk->sk_v6_daddr;
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +0000875 fl6.saddr = saddr ? *saddr : np->saddr;
David S. Miller4c9483b2011-03-12 16:22:43 -0500876 fl6.flowi6_oif = sk->sk_bound_dev_if;
David S. Miller1958b852011-03-12 16:36:19 -0500877 fl6.fl6_dport = usin->sin6_port;
878 fl6.fl6_sport = inet->inet_sport;
David S. Miller4c9483b2011-03-12 16:22:43 -0500879 security_sk_classify_flow(sk, flowi6_to_flowi(&fl6));
Gerrit Renker73c9e022006-11-10 13:01:31 -0200880
Hannes Frederic Sowa1e1d04e2016-04-05 17:10:15 +0200881 opt = rcu_dereference_protected(np->opt, lockdep_sock_is_held(sk));
Eric Dumazet45f6fad2015-11-29 19:37:57 -0800882 final_p = fl6_update_dst(&fl6, opt, &final);
Gerrit Renker73c9e022006-11-10 13:01:31 -0200883
Steffen Klassert0e0d44a2013-08-28 08:04:14 +0200884 dst = ip6_dst_lookup_flow(sk, &fl6, final_p);
David S. Miller68d0c6d2011-03-01 13:19:07 -0800885 if (IS_ERR(dst)) {
886 err = PTR_ERR(dst);
Gerrit Renker73c9e022006-11-10 13:01:31 -0200887 goto failure;
David S. Miller14e50e52007-05-24 18:17:54 -0700888 }
Gerrit Renker73c9e022006-11-10 13:01:31 -0200889
890 if (saddr == NULL) {
David S. Miller4c9483b2011-03-12 16:22:43 -0500891 saddr = &fl6.saddr;
Eric Dumazetefe42082013-10-03 15:42:29 -0700892 sk->sk_v6_rcv_saddr = *saddr;
Gerrit Renker73c9e022006-11-10 13:01:31 -0200893 }
894
895 /* set the source address */
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +0000896 np->saddr = *saddr;
Eric Dumazetc720c7e2009-10-15 06:30:45 +0000897 inet->inet_rcv_saddr = LOOPBACK4_IPV6;
Gerrit Renker73c9e022006-11-10 13:01:31 -0200898
Eric Dumazet6bd4f352015-12-02 21:53:57 -0800899 ip6_dst_store(sk, dst, NULL, NULL);
Gerrit Renker73c9e022006-11-10 13:01:31 -0200900
901 icsk->icsk_ext_hdr_len = 0;
Eric Dumazet45f6fad2015-11-29 19:37:57 -0800902 if (opt)
903 icsk->icsk_ext_hdr_len = opt->opt_flen + opt->opt_nflen;
Gerrit Renker73c9e022006-11-10 13:01:31 -0200904
Eric Dumazetc720c7e2009-10-15 06:30:45 +0000905 inet->inet_dport = usin->sin6_port;
Gerrit Renker73c9e022006-11-10 13:01:31 -0200906
907 dccp_set_state(sk, DCCP_REQUESTING);
908 err = inet6_hash_connect(&dccp_death_row, sk);
909 if (err)
910 goto late_failure;
Gerrit Renkerd7f73652006-11-13 13:34:38 -0200911
912 dp->dccps_iss = secure_dccpv6_sequence_number(np->saddr.s6_addr32,
Eric Dumazetefe42082013-10-03 15:42:29 -0700913 sk->sk_v6_daddr.s6_addr32,
Eric Dumazetc720c7e2009-10-15 06:30:45 +0000914 inet->inet_sport,
915 inet->inet_dport);
Gerrit Renker73c9e022006-11-10 13:01:31 -0200916 err = dccp_connect(sk);
917 if (err)
918 goto late_failure;
919
920 return 0;
921
922late_failure:
923 dccp_set_state(sk, DCCP_CLOSED);
924 __sk_dst_reset(sk);
925failure:
Eric Dumazetc720c7e2009-10-15 06:30:45 +0000926 inet->inet_dport = 0;
Gerrit Renker73c9e022006-11-10 13:01:31 -0200927 sk->sk_route_caps = 0;
928 return err;
929}
930
Stephen Hemminger3b401a82009-09-01 19:25:04 +0000931static const struct inet_connection_sock_af_ops dccp_ipv6_af_ops = {
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -0800932 .queue_xmit = inet6_csk_xmit,
933 .send_check = dccp_v6_send_check,
934 .rebuild_header = inet6_sk_rebuild_header,
935 .conn_request = dccp_v6_conn_request,
936 .syn_recv_sock = dccp_v6_request_recv_sock,
937 .net_header_len = sizeof(struct ipv6hdr),
938 .setsockopt = ipv6_setsockopt,
939 .getsockopt = ipv6_getsockopt,
940 .addr2sockaddr = inet6_csk_addr2sockaddr,
941 .sockaddr_len = sizeof(struct sockaddr_in6),
Dmitry Mishin3fdadf72006-03-20 22:45:21 -0800942#ifdef CONFIG_COMPAT
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -0800943 .compat_setsockopt = compat_ipv6_setsockopt,
944 .compat_getsockopt = compat_ipv6_getsockopt,
Dmitry Mishin3fdadf72006-03-20 22:45:21 -0800945#endif
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800946};
947
948/*
949 * DCCP over IPv4 via INET6 API
950 */
Stephen Hemminger3b401a82009-09-01 19:25:04 +0000951static const struct inet_connection_sock_af_ops dccp_ipv6_mapped = {
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -0800952 .queue_xmit = ip_queue_xmit,
953 .send_check = dccp_v4_send_check,
954 .rebuild_header = inet_sk_rebuild_header,
955 .conn_request = dccp_v6_conn_request,
956 .syn_recv_sock = dccp_v6_request_recv_sock,
957 .net_header_len = sizeof(struct iphdr),
958 .setsockopt = ipv6_setsockopt,
959 .getsockopt = ipv6_getsockopt,
960 .addr2sockaddr = inet6_csk_addr2sockaddr,
961 .sockaddr_len = sizeof(struct sockaddr_in6),
Dmitry Mishin3fdadf72006-03-20 22:45:21 -0800962#ifdef CONFIG_COMPAT
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -0800963 .compat_setsockopt = compat_ipv6_setsockopt,
964 .compat_getsockopt = compat_ipv6_getsockopt,
Dmitry Mishin3fdadf72006-03-20 22:45:21 -0800965#endif
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800966};
967
968/* NOTE: A lot of things set to zero explicitly by call to
969 * sk_alloc() so need not be done here.
970 */
971static int dccp_v6_init_sock(struct sock *sk)
972{
Arnaldo Carvalho de Melo72478872006-03-20 22:00:37 -0800973 static __u8 dccp_v6_ctl_sock_initialized;
974 int err = dccp_init_sock(sk, dccp_v6_ctl_sock_initialized);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800975
Arnaldo Carvalho de Melo72478872006-03-20 22:00:37 -0800976 if (err == 0) {
977 if (unlikely(!dccp_v6_ctl_sock_initialized))
978 dccp_v6_ctl_sock_initialized = 1;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800979 inet_csk(sk)->icsk_af_ops = &dccp_ipv6_af_ops;
Arnaldo Carvalho de Melo72478872006-03-20 22:00:37 -0800980 }
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800981
982 return err;
983}
984
Brian Haley7d06b2e2008-06-14 17:04:49 -0700985static void dccp_v6_destroy_sock(struct sock *sk)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800986{
Arnaldo Carvalho de Melo3e0fadc2006-03-20 21:23:15 -0800987 dccp_destroy_sock(sk);
Brian Haley7d06b2e2008-06-14 17:04:49 -0700988 inet6_destroy_sock(sk);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800989}
990
Gerrit Renker73c9e022006-11-10 13:01:31 -0200991static struct timewait_sock_ops dccp6_timewait_sock_ops = {
992 .twsk_obj_size = sizeof(struct dccp6_timewait_sock),
993};
994
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800995static struct proto dccp_v6_prot = {
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -0800996 .name = "DCCPv6",
997 .owner = THIS_MODULE,
998 .close = dccp_close,
999 .connect = dccp_v6_connect,
1000 .disconnect = dccp_disconnect,
1001 .ioctl = dccp_ioctl,
1002 .init = dccp_v6_init_sock,
1003 .setsockopt = dccp_setsockopt,
1004 .getsockopt = dccp_getsockopt,
1005 .sendmsg = dccp_sendmsg,
1006 .recvmsg = dccp_recvmsg,
1007 .backlog_rcv = dccp_v6_do_rcv,
Craig Gallek496611d2016-02-10 11:50:36 -05001008 .hash = inet6_hash,
Arnaldo Carvalho de Meloab1e0a12008-02-03 04:06:04 -08001009 .unhash = inet_unhash,
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001010 .accept = inet_csk_accept,
Arnaldo Carvalho de Meloab1e0a12008-02-03 04:06:04 -08001011 .get_port = inet_csk_get_port,
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001012 .shutdown = dccp_shutdown,
1013 .destroy = dccp_v6_destroy_sock,
1014 .orphan_count = &dccp_orphan_count,
1015 .max_header = MAX_DCCP_HEADER,
1016 .obj_size = sizeof(struct dccp6_sock),
Paul E. McKenney5f0d5a32017-01-18 02:53:44 -08001017 .slab_flags = SLAB_TYPESAFE_BY_RCU,
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001018 .rsk_prot = &dccp6_request_sock_ops,
1019 .twsk_prot = &dccp6_timewait_sock_ops,
Pavel Emelyanov39d8cda2008-03-22 16:50:58 -07001020 .h.hashinfo = &dccp_hashinfo,
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001021#ifdef CONFIG_COMPAT
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001022 .compat_setsockopt = compat_dccp_setsockopt,
1023 .compat_getsockopt = compat_dccp_getsockopt,
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001024#endif
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001025};
1026
Alexey Dobriyan41135cc2009-09-14 12:22:28 +00001027static const struct inet6_protocol dccp_v6_protocol = {
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -08001028 .handler = dccp_v6_rcv,
1029 .err_handler = dccp_v6_err,
1030 .flags = INET6_PROTO_NOPOLICY | INET6_PROTO_FINAL,
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001031};
1032
Alexey Dobriyan5708e862009-09-14 12:23:23 +00001033static const struct proto_ops inet6_dccp_ops = {
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001034 .family = PF_INET6,
1035 .owner = THIS_MODULE,
1036 .release = inet6_release,
1037 .bind = inet6_bind,
1038 .connect = inet_stream_connect,
1039 .socketpair = sock_no_socketpair,
1040 .accept = inet_accept,
1041 .getname = inet6_getname,
1042 .poll = dccp_poll,
1043 .ioctl = inet6_ioctl,
1044 .listen = inet_dccp_listen,
1045 .shutdown = inet_shutdown,
1046 .setsockopt = sock_common_setsockopt,
1047 .getsockopt = sock_common_getsockopt,
1048 .sendmsg = inet_sendmsg,
1049 .recvmsg = sock_common_recvmsg,
1050 .mmap = sock_no_mmap,
1051 .sendpage = sock_no_sendpage,
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001052#ifdef CONFIG_COMPAT
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001053 .compat_setsockopt = compat_sock_common_setsockopt,
1054 .compat_getsockopt = compat_sock_common_getsockopt,
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001055#endif
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001056};
1057
1058static struct inet_protosw dccp_v6_protosw = {
1059 .type = SOCK_DCCP,
1060 .protocol = IPPROTO_DCCP,
1061 .prot = &dccp_v6_prot,
1062 .ops = &inet6_dccp_ops,
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -08001063 .flags = INET_PROTOSW_ICSK,
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001064};
1065
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00001066static int __net_init dccp_v6_init_net(struct net *net)
Pavel Emelyanov8231bd22008-04-13 22:32:02 -07001067{
Gerrit Renkerd14a0eb2010-03-14 20:13:19 +00001068 if (dccp_hashinfo.bhash == NULL)
1069 return -ESOCKTNOSUPPORT;
Pavel Emelyanov334527d2008-04-13 22:32:45 -07001070
Gerrit Renkerd14a0eb2010-03-14 20:13:19 +00001071 return inet_ctl_sock_create(&net->dccp.v6_ctl_sk, PF_INET6,
1072 SOCK_DCCP, IPPROTO_DCCP, net);
Pavel Emelyanov8231bd22008-04-13 22:32:02 -07001073}
1074
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00001075static void __net_exit dccp_v6_exit_net(struct net *net)
Pavel Emelyanov8231bd22008-04-13 22:32:02 -07001076{
Pavel Emelyanov334527d2008-04-13 22:32:45 -07001077 inet_ctl_sock_destroy(net->dccp.v6_ctl_sk);
Pavel Emelyanov8231bd22008-04-13 22:32:02 -07001078}
1079
Andrey Ryabininec7cb622017-02-22 12:35:27 +03001080static void __net_exit dccp_v6_exit_batch(struct list_head *net_exit_list)
1081{
1082 inet_twsk_purge(&dccp_hashinfo, AF_INET6);
1083}
1084
Pavel Emelyanov8231bd22008-04-13 22:32:02 -07001085static struct pernet_operations dccp_v6_ops = {
1086 .init = dccp_v6_init_net,
1087 .exit = dccp_v6_exit_net,
Andrey Ryabininec7cb622017-02-22 12:35:27 +03001088 .exit_batch = dccp_v6_exit_batch,
Pavel Emelyanov8231bd22008-04-13 22:32:02 -07001089};
1090
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001091static int __init dccp_v6_init(void)
1092{
1093 int err = proto_register(&dccp_v6_prot, 1);
1094
1095 if (err != 0)
1096 goto out;
1097
1098 err = inet6_add_protocol(&dccp_v6_protocol, IPPROTO_DCCP);
1099 if (err != 0)
1100 goto out_unregister_proto;
1101
1102 inet6_register_protosw(&dccp_v6_protosw);
Arnaldo Carvalho de Melo72478872006-03-20 22:00:37 -08001103
Pavel Emelyanov8231bd22008-04-13 22:32:02 -07001104 err = register_pernet_subsys(&dccp_v6_ops);
1105 if (err != 0)
1106 goto out_destroy_ctl_sock;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001107out:
1108 return err;
Pavel Emelyanov8231bd22008-04-13 22:32:02 -07001109
1110out_destroy_ctl_sock:
Arnaldo Carvalho de Melo72478872006-03-20 22:00:37 -08001111 inet6_del_protocol(&dccp_v6_protocol, IPPROTO_DCCP);
1112 inet6_unregister_protosw(&dccp_v6_protosw);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001113out_unregister_proto:
1114 proto_unregister(&dccp_v6_prot);
1115 goto out;
1116}
1117
1118static void __exit dccp_v6_exit(void)
1119{
Pavel Emelyanov8231bd22008-04-13 22:32:02 -07001120 unregister_pernet_subsys(&dccp_v6_ops);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001121 inet6_del_protocol(&dccp_v6_protocol, IPPROTO_DCCP);
1122 inet6_unregister_protosw(&dccp_v6_protosw);
1123 proto_unregister(&dccp_v6_prot);
1124}
1125
1126module_init(dccp_v6_init);
1127module_exit(dccp_v6_exit);
1128
1129/*
1130 * __stringify doesn't likes enums, so use SOCK_DCCP (6) and IPPROTO_DCCP (33)
1131 * values directly, Also cover the case where the protocol is not specified,
1132 * i.e. net-pf-PF_INET6-proto-0-type-SOCK_DCCP
1133 */
Jean Delvare7131c6c2007-10-21 16:45:03 -07001134MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_INET6, 33, 6);
1135MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_INET6, 0, 6);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001136MODULE_LICENSE("GPL");
1137MODULE_AUTHOR("Arnaldo Carvalho de Melo <acme@mandriva.com>");
1138MODULE_DESCRIPTION("DCCPv6 - Datagram Congestion Controlled Protocol");