blob: 1b7381ff787b388488a8458b6f52760f73a4f22d [file] [log] [blame]
Thomas Gleixner2874c5f2019-05-27 08:55:01 +02001// SPDX-License-Identifier: GPL-2.0-or-later
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08002/*
3 * DCCP over IPv6
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -08004 * Linux INET6 implementation
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08005 *
6 * Based on net/dccp6/ipv6.c
7 *
8 * Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08009 */
10
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -080011#include <linux/module.h>
12#include <linux/random.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090013#include <linux/slab.h>
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -080014#include <linux/xfrm.h>
Andrii323fbd02017-08-31 08:28:01 +030015#include <linux/string.h>
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -080016
17#include <net/addrconf.h>
18#include <net/inet_common.h>
19#include <net/inet_hashtables.h>
Arnaldo Carvalho de Melo14c85022005-12-27 02:43:12 -020020#include <net/inet_sock.h>
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -080021#include <net/inet6_connection_sock.h>
22#include <net/inet6_hashtables.h>
23#include <net/ip6_route.h>
24#include <net/ipv6.h>
25#include <net/protocol.h>
26#include <net/transp_v6.h>
David S. Milleraa0e4e42006-01-06 22:55:39 -080027#include <net/ip6_checksum.h>
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -080028#include <net/xfrm.h>
David S. Miller6e5714e2011-08-03 20:50:44 -070029#include <net/secure_seq.h>
Andrii323fbd02017-08-31 08:28:01 +030030#include <net/sock.h>
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -080031
32#include "dccp.h"
33#include "ipv6.h"
Ian McDonald4b79f0a2006-07-23 23:33:28 -070034#include "feat.h"
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -080035
Pavel Emelyanov13f51d82008-04-14 02:38:45 -070036/* The per-net dccp.v6_ctl_sk is used for sending RSTs and ACKs */
Arnaldo Carvalho de Melo72478872006-03-20 22:00:37 -080037
Stephen Hemminger3b401a82009-09-01 19:25:04 +000038static const struct inet_connection_sock_af_ops dccp_ipv6_mapped;
39static const struct inet_connection_sock_af_ops dccp_ipv6_af_ops;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -080040
Gerrit Renker6f4e5ff2006-11-10 17:43:06 -020041/* add pseudo-header to DCCP checksum stored in skb->csum */
Al Viro868c86b2006-11-14 21:35:48 -080042static inline __sum16 dccp_v6_csum_finish(struct sk_buff *skb,
Eric Dumazetb71d1d42011-04-22 04:53:02 +000043 const struct in6_addr *saddr,
44 const struct in6_addr *daddr)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -080045{
Gerrit Renker6f4e5ff2006-11-10 17:43:06 -020046 return csum_ipv6_magic(saddr, daddr, skb->len, IPPROTO_DCCP, skb->csum);
47}
48
Herbert Xubb296242010-04-11 02:15:55 +000049static inline void dccp_v6_send_check(struct sock *sk, struct sk_buff *skb)
Gerrit Renker6f4e5ff2006-11-10 17:43:06 -020050{
51 struct ipv6_pinfo *np = inet6_sk(sk);
52 struct dccp_hdr *dh = dccp_hdr(skb);
53
54 dccp_csum_outgoing(skb);
Eric Dumazetefe42082013-10-03 15:42:29 -070055 dh->dccph_checksum = dccp_v6_csum_finish(skb, &np->saddr, &sk->sk_v6_daddr);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -080056}
57
David S. Miller6e5714e2011-08-03 20:50:44 -070058static inline __u64 dccp_v6_init_sequence(struct sk_buff *skb)
Gerrit Renkerd7f73652006-11-13 13:34:38 -020059{
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -070060 return secure_dccpv6_sequence_number(ipv6_hdr(skb)->daddr.s6_addr32,
61 ipv6_hdr(skb)->saddr.s6_addr32,
Gerrit Renkerd7f73652006-11-13 13:34:38 -020062 dccp_hdr(skb)->dccph_dport,
63 dccp_hdr(skb)->dccph_sport );
64
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -080065}
66
Stefano Brivio32bbd872018-11-08 12:19:21 +010067static int dccp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
Brian Haleyd5fdd6b2009-06-23 04:31:07 -070068 u8 type, u8 code, int offset, __be32 info)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -080069{
Eric Dumazetb71d1d42011-04-22 04:53:02 +000070 const struct ipv6hdr *hdr = (const struct ipv6hdr *)skb->data;
Eric Dumazet1aa9d1a2016-11-02 20:30:48 -070071 const struct dccp_hdr *dh;
Wei Yongjune0bcfb02008-07-26 11:59:10 +010072 struct dccp_sock *dp;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -080073 struct ipv6_pinfo *np;
74 struct sock *sk;
75 int err;
76 __u64 seq;
Pavel Emelyanovca12a1a2008-07-16 20:28:42 -070077 struct net *net = dev_net(skb->dev);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -080078
Eric Dumazet1aa9d1a2016-11-02 20:30:48 -070079 /* Only need dccph_dport & dccph_sport which are the first
80 * 4 bytes in dccp header.
81 * Our caller (icmpv6_notify()) already pulled 8 bytes for us.
82 */
83 BUILD_BUG_ON(offsetofend(struct dccp_hdr, dccph_sport) > 8);
84 BUILD_BUG_ON(offsetofend(struct dccp_hdr, dccph_dport) > 8);
85 dh = (struct dccp_hdr *)(skb->data + offset);
Wei Yongjun860239c2008-07-26 11:59:11 +010086
Eric Dumazet52036a42015-03-22 10:22:25 -070087 sk = __inet6_lookup_established(net, &dccp_hashinfo,
88 &hdr->daddr, dh->dccph_dport,
89 &hdr->saddr, ntohs(dh->dccph_sport),
David Ahern4297a0e2017-08-07 08:44:21 -070090 inet6_iif(skb), 0);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -080091
Eric Dumazet52036a42015-03-22 10:22:25 -070092 if (!sk) {
Eric Dumazeta16292a2016-04-27 16:44:36 -070093 __ICMP6_INC_STATS(net, __in6_dev_get(skb->dev),
94 ICMP6_MIB_INERRORS);
Stefano Brivio32bbd872018-11-08 12:19:21 +010095 return -ENOENT;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -080096 }
97
98 if (sk->sk_state == DCCP_TIME_WAIT) {
YOSHIFUJI Hideaki9469c7b2006-10-10 19:41:46 -070099 inet_twsk_put(inet_twsk(sk));
Stefano Brivio32bbd872018-11-08 12:19:21 +0100100 return 0;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800101 }
Eric Dumazet52036a42015-03-22 10:22:25 -0700102 seq = dccp_hdr_seq(dh);
Stefano Brivio32bbd872018-11-08 12:19:21 +0100103 if (sk->sk_state == DCCP_NEW_SYN_RECV) {
104 dccp_req_err(sk, seq);
105 return 0;
106 }
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);
Stefano Brivio32bbd872018-11-08 12:19:21 +0100184 return 0;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800185}
186
187
Eric Dumazetea3bea32015-09-25 07:39:23 -0700188static int dccp_v6_send_response(const struct sock *sk, struct request_sock *req)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800189{
Eric Dumazet634fb9792013-10-09 15:21:29 -0700190 struct inet_request_sock *ireq = inet_rsk(req);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800191 struct ipv6_pinfo *np = inet6_sk(sk);
192 struct sk_buff *skb;
Arnaud Ebalard20c59de2010-06-01 21:35:01 +0000193 struct in6_addr *final_p, final;
David S. Miller4c9483b2011-03-12 16:22:43 -0500194 struct flowi6 fl6;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800195 int err = -1;
Denis V. Lunevfd80eb92008-02-29 11:43:03 -0800196 struct dst_entry *dst;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800197
David S. Miller4c9483b2011-03-12 16:22:43 -0500198 memset(&fl6, 0, sizeof(fl6));
199 fl6.flowi6_proto = IPPROTO_DCCP;
Eric Dumazet634fb9792013-10-09 15:21:29 -0700200 fl6.daddr = ireq->ir_v6_rmt_addr;
201 fl6.saddr = ireq->ir_v6_loc_addr;
David S. Miller4c9483b2011-03-12 16:22:43 -0500202 fl6.flowlabel = 0;
Eric Dumazet634fb9792013-10-09 15:21:29 -0700203 fl6.flowi6_oif = ireq->ir_iif;
204 fl6.fl6_dport = ireq->ir_rmt_port;
Eric Dumazetb44084c2013-10-10 00:04:37 -0700205 fl6.fl6_sport = htons(ireq->ir_num);
David S. Miller4c9483b2011-03-12 16:22:43 -0500206 security_req_classify_flow(req, flowi6_to_flowi(&fl6));
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800207
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800208
Eric Dumazet45f6fad2015-11-29 19:37:57 -0800209 rcu_read_lock();
210 final_p = fl6_update_dst(&fl6, rcu_dereference(np->opt), &final);
211 rcu_read_unlock();
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800212
Steffen Klassert0e0d44a2013-08-28 08:04:14 +0200213 dst = ip6_dst_lookup_flow(sk, &fl6, final_p);
David S. Miller68d0c6d2011-03-01 13:19:07 -0800214 if (IS_ERR(dst)) {
215 err = PTR_ERR(dst);
216 dst = NULL;
Denis V. Lunevfd80eb92008-02-29 11:43:03 -0800217 goto done;
David S. Miller68d0c6d2011-03-01 13:19:07 -0800218 }
Denis V. Lunevfd80eb92008-02-29 11:43:03 -0800219
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800220 skb = dccp_make_response(sk, dst, req);
221 if (skb != NULL) {
222 struct dccp_hdr *dh = dccp_hdr(skb);
Huw Davies56ac42b2016-06-27 15:05:28 -0400223 struct ipv6_txoptions *opt;
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800224
Gerrit Renker6f4e5ff2006-11-10 17:43:06 -0200225 dh->dccph_checksum = dccp_v6_csum_finish(skb,
Eric Dumazet634fb9792013-10-09 15:21:29 -0700226 &ireq->ir_v6_loc_addr,
227 &ireq->ir_v6_rmt_addr);
228 fl6.daddr = ireq->ir_v6_rmt_addr;
Eric Dumazet45f6fad2015-11-29 19:37:57 -0800229 rcu_read_lock();
Huw Davies56ac42b2016-06-27 15:05:28 -0400230 opt = ireq->ipv6_opt;
231 if (!opt)
232 opt = rcu_dereference(np->opt);
Pablo Neira92e55f42017-01-26 22:56:21 +0100233 err = ip6_xmit(sk, skb, &fl6, sk->sk_mark, opt, np->tclass);
Eric Dumazet45f6fad2015-11-29 19:37:57 -0800234 rcu_read_unlock();
Gerrit Renkerb9df3cb2006-11-14 11:21:36 -0200235 err = net_xmit_eval(err);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800236 }
237
238done:
David S. Miller0cbd7822006-01-31 17:53:37 -0800239 dst_release(dst);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800240 return err;
241}
242
243static void dccp_v6_reqsk_destructor(struct request_sock *req)
244{
Gerrit Renkerd99a7bd2008-11-04 23:56:30 -0800245 dccp_feat_list_purge(&dccp_rsk(req)->dreq_featneg);
Huw Davies56ac42b2016-06-27 15:05:28 -0400246 kfree(inet_rsk(req)->ipv6_opt);
Eric Dumazet634fb9792013-10-09 15:21:29 -0700247 kfree_skb(inet_rsk(req)->pktopts);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800248}
249
Eric Dumazeta00e7442015-09-29 07:42:39 -0700250static void dccp_v6_ctl_send_reset(const struct sock *sk, struct sk_buff *rxskb)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800251{
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000252 const struct ipv6hdr *rxip6h;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800253 struct sk_buff *skb;
David S. Miller4c9483b2011-03-12 16:22:43 -0500254 struct flowi6 fl6;
Eric Dumazetadf30902009-06-02 05:19:30 +0000255 struct net *net = dev_net(skb_dst(rxskb)->dev);
Pavel Emelyanov334527d2008-04-13 22:32:45 -0700256 struct sock *ctl_sk = net->dccp.v6_ctl_sk;
Eric Dumazetadf30902009-06-02 05:19:30 +0000257 struct dst_entry *dst;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800258
Gerrit Renkere356d372007-09-26 14:35:19 -0300259 if (dccp_hdr(rxskb)->dccph_type == DCCP_PKT_RESET)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800260 return;
261
262 if (!ipv6_unicast_destination(rxskb))
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800263 return;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800264
Pavel Emelyanov02047742008-04-13 22:32:25 -0700265 skb = dccp_ctl_make_reset(ctl_sk, rxskb);
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800266 if (skb == NULL)
Arnaldo Carvalho de Melo8109b022006-12-10 16:01:18 -0200267 return;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800268
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700269 rxip6h = ipv6_hdr(rxskb);
Gerrit Renkere356d372007-09-26 14:35:19 -0300270 dccp_hdr(skb)->dccph_checksum = dccp_v6_csum_finish(skb, &rxip6h->saddr,
271 &rxip6h->daddr);
Gerrit Renker6f4e5ff2006-11-10 17:43:06 -0200272
David S. Miller4c9483b2011-03-12 16:22:43 -0500273 memset(&fl6, 0, sizeof(fl6));
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +0000274 fl6.daddr = rxip6h->saddr;
275 fl6.saddr = rxip6h->daddr;
Gerrit Renker6f4e5ff2006-11-10 17:43:06 -0200276
David S. Miller4c9483b2011-03-12 16:22:43 -0500277 fl6.flowi6_proto = IPPROTO_DCCP;
278 fl6.flowi6_oif = inet6_iif(rxskb);
David S. Miller1958b852011-03-12 16:36:19 -0500279 fl6.fl6_dport = dccp_hdr(skb)->dccph_dport;
280 fl6.fl6_sport = dccp_hdr(skb)->dccph_sport;
David S. Miller4c9483b2011-03-12 16:22:43 -0500281 security_skb_classify_flow(rxskb, flowi6_to_flowi(&fl6));
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800282
283 /* sk = NULL, but it is safe for now. RST socket required. */
Steffen Klassert0e0d44a2013-08-28 08:04:14 +0200284 dst = ip6_dst_lookup_flow(ctl_sk, &fl6, NULL);
David S. Miller68d0c6d2011-03-01 13:19:07 -0800285 if (!IS_ERR(dst)) {
286 skb_dst_set(skb, dst);
Pablo Neira92e55f42017-01-26 22:56:21 +0100287 ip6_xmit(ctl_sk, skb, &fl6, 0, NULL, 0);
Eric Dumazet7309f882016-04-29 14:16:49 -0700288 DCCP_INC_STATS(DCCP_MIB_OUTSEGS);
289 DCCP_INC_STATS(DCCP_MIB_OUTRSTS);
David S. Miller68d0c6d2011-03-01 13:19:07 -0800290 return;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800291 }
292
293 kfree_skb(skb);
294}
295
Gerrit Renker73c9e022006-11-10 13:01:31 -0200296static struct request_sock_ops dccp6_request_sock_ops = {
297 .family = AF_INET6,
298 .obj_size = sizeof(struct dccp6_request_sock),
299 .rtx_syn_ack = dccp_v6_send_response,
300 .send_ack = dccp_reqsk_send_ack,
301 .destructor = dccp_v6_reqsk_destructor,
302 .send_reset = dccp_v6_ctl_send_reset,
Eric Dumazetc72e1182012-04-12 22:16:05 +0000303 .syn_ack_timeout = dccp_syn_ack_timeout,
Gerrit Renker73c9e022006-11-10 13:01:31 -0200304};
305
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800306static int dccp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
307{
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800308 struct request_sock *req;
309 struct dccp_request_sock *dreq;
Eric Dumazet634fb9792013-10-09 15:21:29 -0700310 struct inet_request_sock *ireq;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800311 struct ipv6_pinfo *np = inet6_sk(sk);
Arnaldo Carvalho de Melo8109b022006-12-10 16:01:18 -0200312 const __be32 service = dccp_hdr_request(skb)->dccph_req_service;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800313 struct dccp_skb_cb *dcb = DCCP_SKB_CB(skb);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800314
315 if (skb->protocol == htons(ETH_P_IP))
316 return dccp_v4_conn_request(sk, skb);
317
318 if (!ipv6_unicast_destination(skb))
Gerrit Renker4a5409a2007-10-04 14:52:28 -0700319 return 0; /* discard, don't send a reset here */
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800320
321 if (dccp_bad_service_code(sk, service)) {
Gerrit Renker4a5409a2007-10-04 14:52:28 -0700322 dcb->dccpd_reset_code = DCCP_RESET_CODE_BAD_SERVICE_CODE;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800323 goto drop;
Arnaldo Carvalho de Melo8109b022006-12-10 16:01:18 -0200324 }
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800325 /*
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800326 * There are no SYN attacks on IPv6, yet...
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800327 */
Gerrit Renker4a5409a2007-10-04 14:52:28 -0700328 dcb->dccpd_reset_code = DCCP_RESET_CODE_TOO_BUSY;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800329 if (inet_csk_reqsk_queue_is_full(sk))
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800330 goto drop;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800331
Eric Dumazet5ea8ea22016-10-26 09:27:57 -0700332 if (sk_acceptq_is_full(sk))
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800333 goto drop;
334
Eric Dumazeta1a53442015-10-04 21:08:11 -0700335 req = inet_reqsk_alloc(&dccp6_request_sock_ops, sk, true);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800336 if (req == NULL)
337 goto drop;
338
Gerrit Renkerac757732008-11-04 23:55:49 -0800339 if (dccp_reqsk_init(req, dccp_sk(sk), skb))
340 goto drop_and_free;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800341
Gerrit Renker8b819412007-12-13 12:29:24 -0200342 dreq = dccp_rsk(req);
343 if (dccp_parse_options(sk, dreq, skb))
344 goto drop_and_free;
345
Venkat Yekkirala4237c752006-07-24 23:32:50 -0700346 if (security_inet_conn_request(sk, skb, req))
347 goto drop_and_free;
348
Eric Dumazet634fb9792013-10-09 15:21:29 -0700349 ireq = inet_rsk(req);
350 ireq->ir_v6_rmt_addr = ipv6_hdr(skb)->saddr;
351 ireq->ir_v6_loc_addr = ipv6_hdr(skb)->daddr;
Eric Dumazet3f66b082015-03-12 16:44:10 -0700352 ireq->ireq_family = AF_INET6;
Eric Dumazetb855ff82018-04-07 13:42:41 -0700353 ireq->ir_mark = inet_request_mark(sk, skb);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800354
Eric Dumazeta2247722014-09-27 09:50:56 -0700355 if (ipv6_opt_accepted(sk, skb, IP6CB(skb)) ||
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800356 np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo ||
357 np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim) {
Reshetova, Elena63354792017-06-30 13:07:58 +0300358 refcount_inc(&skb->users);
Eric Dumazet634fb9792013-10-09 15:21:29 -0700359 ireq->pktopts = skb;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800360 }
Eric Dumazet634fb9792013-10-09 15:21:29 -0700361 ireq->ir_iif = sk->sk_bound_dev_if;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800362
363 /* So that link locals have meaning */
364 if (!sk->sk_bound_dev_if &&
Eric Dumazet634fb9792013-10-09 15:21:29 -0700365 ipv6_addr_type(&ireq->ir_v6_rmt_addr) & IPV6_ADDR_LINKLOCAL)
366 ireq->ir_iif = inet6_iif(skb);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800367
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800368 /*
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800369 * Step 3: Process LISTEN state
370 *
Gerrit Renkerd83ca5a2006-11-10 16:29:14 -0200371 * Set S.ISR, S.GSR, S.SWL, S.SWH from packet or Init Cookie
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800372 *
Samuel Jerof541fb72012-02-26 18:22:02 -0700373 * Setting S.SWL/S.SWH to is deferred to dccp_create_openreq_child().
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800374 */
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800375 dreq->dreq_isr = dcb->dccpd_seq;
Samuel Jerof541fb72012-02-26 18:22:02 -0700376 dreq->dreq_gsr = dreq->dreq_isr;
Gerrit Renker865e9022006-11-13 13:31:50 -0200377 dreq->dreq_iss = dccp_v6_init_sequence(skb);
Samuel Jerof541fb72012-02-26 18:22:02 -0700378 dreq->dreq_gss = dreq->dreq_iss;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800379 dreq->dreq_service = service;
380
Christoph Paasch1a2c6182013-03-17 08:23:34 +0000381 if (dccp_v6_send_response(sk, req))
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800382 goto drop_and_free;
383
Eric Dumazet079096f2015-10-02 11:43:32 -0700384 inet_csk_reqsk_queue_hash_add(sk, req, DCCP_TIMEOUT_INIT);
Xin Long0c2232b2017-07-26 14:19:09 +0800385 reqsk_put(req);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800386 return 0;
387
388drop_and_free:
389 reqsk_free(req);
390drop:
Eric Dumazetaa62d762016-04-27 16:44:28 -0700391 __DCCP_INC_STATS(DCCP_MIB_ATTEMPTFAILS);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800392 return -1;
393}
394
Eric Dumazet0c271712015-09-29 07:42:48 -0700395static struct sock *dccp_v6_request_recv_sock(const struct sock *sk,
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800396 struct sk_buff *skb,
397 struct request_sock *req,
Eric Dumazet5e0724d2015-10-22 08:20:46 -0700398 struct dst_entry *dst,
399 struct request_sock *req_unhash,
400 bool *own_req)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800401{
Eric Dumazet634fb9792013-10-09 15:21:29 -0700402 struct inet_request_sock *ireq = inet_rsk(req);
Eric Dumazet0c271712015-09-29 07:42:48 -0700403 struct ipv6_pinfo *newnp;
404 const struct ipv6_pinfo *np = inet6_sk(sk);
Eric Dumazet45f6fad2015-11-29 19:37:57 -0800405 struct ipv6_txoptions *opt;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800406 struct inet_sock *newinet;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800407 struct dccp6_sock *newdp6;
408 struct sock *newsk;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800409
410 if (skb->protocol == htons(ETH_P_IP)) {
411 /*
412 * v6 mapped
413 */
Eric Dumazet5e0724d2015-10-22 08:20:46 -0700414 newsk = dccp_v4_request_recv_sock(sk, skb, req, dst,
415 req_unhash, own_req);
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800416 if (newsk == NULL)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800417 return NULL;
418
419 newdp6 = (struct dccp6_sock *)newsk;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800420 newinet = inet_sk(newsk);
421 newinet->pinet6 = &newdp6->inet6;
422 newnp = inet6_sk(newsk);
423
424 memcpy(newnp, np, sizeof(struct ipv6_pinfo));
425
Eric Dumazetd1e559d2015-03-18 14:05:35 -0700426 newnp->saddr = newsk->sk_v6_rcv_saddr;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800427
428 inet_csk(newsk)->icsk_af_ops = &dccp_ipv6_mapped;
429 newsk->sk_backlog_rcv = dccp_v4_do_rcv;
430 newnp->pktoptions = NULL;
431 newnp->opt = NULL;
WANG Cong83eadda2017-05-09 16:59:54 -0700432 newnp->ipv6_mc_list = NULL;
433 newnp->ipv6_ac_list = NULL;
434 newnp->ipv6_fl_list = NULL;
Eric Dumazete0aa6772019-03-19 05:46:18 -0700435 newnp->mcast_oif = inet_iif(skb);
436 newnp->mcast_hops = ip_hdr(skb)->ttl;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800437
438 /*
439 * No need to charge this sock to the relevant IPv6 refcnt debug socks count
440 * here, dccp_create_openreq_child now does this for us, see the comment in
441 * that function for the gory details. -acme
442 */
443
444 /* It is tricky place. Until this moment IPv4 tcp
445 worked with IPv6 icsk.icsk_af_ops.
446 Sync it now.
447 */
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -0800448 dccp_sync_mss(newsk, inet_csk(newsk)->icsk_pmtu_cookie);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800449
450 return newsk;
451 }
452
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800453
454 if (sk_acceptq_is_full(sk))
455 goto out_overflow;
456
Eric Dumazetf76b33c2015-09-29 07:42:42 -0700457 if (!dst) {
David S. Miller4c9483b2011-03-12 16:22:43 -0500458 struct flowi6 fl6;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800459
Eric Dumazetf76b33c2015-09-29 07:42:42 -0700460 dst = inet6_csk_route_req(sk, &fl6, req, IPPROTO_DCCP);
461 if (!dst)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800462 goto out;
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800463 }
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800464
465 newsk = dccp_create_openreq_child(sk, req, skb);
466 if (newsk == NULL)
Balazs Scheidler093d2822010-10-21 13:06:43 +0200467 goto out_nonewsk;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800468
469 /*
470 * No need to charge this sock to the relevant IPv6 refcnt debug socks
471 * count here, dccp_create_openreq_child now does this for us, see the
472 * comment in that function for the gory details. -acme
473 */
474
Eric Dumazet6bd4f352015-12-02 21:53:57 -0800475 ip6_dst_store(newsk, dst, NULL, NULL);
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800476 newsk->sk_route_caps = dst->dev->features & ~(NETIF_F_IP_CSUM |
477 NETIF_F_TSO);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800478 newdp6 = (struct dccp6_sock *)newsk;
479 newinet = inet_sk(newsk);
480 newinet->pinet6 = &newdp6->inet6;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800481 newnp = inet6_sk(newsk);
482
483 memcpy(newnp, np, sizeof(struct ipv6_pinfo));
484
Eric Dumazet634fb9792013-10-09 15:21:29 -0700485 newsk->sk_v6_daddr = ireq->ir_v6_rmt_addr;
486 newnp->saddr = ireq->ir_v6_loc_addr;
487 newsk->sk_v6_rcv_saddr = ireq->ir_v6_loc_addr;
488 newsk->sk_bound_dev_if = ireq->ir_iif;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800489
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800490 /* Now IPv6 options...
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800491
492 First: no IPv4 options.
493 */
Eric Dumazetf6d8bd02011-04-21 09:45:37 +0000494 newinet->inet_opt = NULL;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800495
496 /* Clone RX bits */
497 newnp->rxopt.all = np->rxopt.all;
498
WANG Cong83eadda2017-05-09 16:59:54 -0700499 newnp->ipv6_mc_list = NULL;
500 newnp->ipv6_ac_list = NULL;
501 newnp->ipv6_fl_list = NULL;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800502 newnp->pktoptions = NULL;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800503 newnp->opt = NULL;
504 newnp->mcast_oif = inet6_iif(skb);
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700505 newnp->mcast_hops = ipv6_hdr(skb)->hop_limit;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800506
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800507 /*
508 * Clone native IPv6 options from listening socket (if any)
509 *
510 * Yes, keeping reference count would be much more clever, but we make
511 * one more one thing there: reattach optmem to newsk.
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800512 */
Huw Davies56ac42b2016-06-27 15:05:28 -0400513 opt = ireq->ipv6_opt;
514 if (!opt)
515 opt = rcu_dereference(np->opt);
Eric Dumazet45f6fad2015-11-29 19:37:57 -0800516 if (opt) {
517 opt = ipv6_dup_options(newsk, opt);
518 RCU_INIT_POINTER(newnp->opt, opt);
519 }
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -0800520 inet_csk(newsk)->icsk_ext_hdr_len = 0;
Eric Dumazet45f6fad2015-11-29 19:37:57 -0800521 if (opt)
522 inet_csk(newsk)->icsk_ext_hdr_len = opt->opt_nflen +
523 opt->opt_flen;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800524
525 dccp_sync_mss(newsk, dst_mtu(dst));
526
Eric Dumazetc720c7e82009-10-15 06:30:45 +0000527 newinet->inet_daddr = newinet->inet_saddr = LOOPBACK4_IPV6;
528 newinet->inet_rcv_saddr = LOOPBACK4_IPV6;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800529
Balazs Scheidler093d2822010-10-21 13:06:43 +0200530 if (__inet_inherit_port(sk, newsk) < 0) {
Christoph Paasche337e242012-12-14 04:07:58 +0000531 inet_csk_prepare_forced_close(newsk);
532 dccp_done(newsk);
Balazs Scheidler093d2822010-10-21 13:06:43 +0200533 goto out;
534 }
Eric Dumazet5e0724d2015-10-22 08:20:46 -0700535 *own_req = inet_ehash_nolisten(newsk, req_to_sk(req_unhash));
Eric Dumazetce105002015-10-30 09:46:12 -0700536 /* Clone pktoptions received with SYN, if we own the req */
537 if (*own_req && ireq->pktopts) {
538 newnp->pktoptions = skb_clone(ireq->pktopts, GFP_ATOMIC);
539 consume_skb(ireq->pktopts);
540 ireq->pktopts = NULL;
541 if (newnp->pktoptions)
542 skb_set_owner_r(newnp->pktoptions, newsk);
543 }
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800544
545 return newsk;
546
547out_overflow:
Eric Dumazet02a1d6e2016-04-27 16:44:39 -0700548 __NET_INC_STATS(sock_net(sk), LINUX_MIB_LISTENOVERFLOWS);
Balazs Scheidler093d2822010-10-21 13:06:43 +0200549out_nonewsk:
550 dst_release(dst);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800551out:
Eric Dumazet02a1d6e2016-04-27 16:44:39 -0700552 __NET_INC_STATS(sock_net(sk), LINUX_MIB_LISTENDROPS);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800553 return NULL;
554}
555
556/* The socket must have it's spinlock held when we get
557 * here.
558 *
559 * We have a potential double-lock case here, so even when
560 * doing backlog processing we use the BH locking scheme.
561 * This is because we cannot sleep with the original spinlock
562 * held.
563 */
564static int dccp_v6_do_rcv(struct sock *sk, struct sk_buff *skb)
565{
566 struct ipv6_pinfo *np = inet6_sk(sk);
567 struct sk_buff *opt_skb = NULL;
568
569 /* Imagine: socket is IPv6. IPv4 packet arrives,
570 goes to IPv4 receive handler and backlogged.
571 From backlog it always goes here. Kerboom...
572 Fortunately, dccp_rcv_established and rcv_established
573 handle them correctly, but it is not case with
574 dccp_v6_hnd_req and dccp_v6_ctl_send_reset(). --ANK
575 */
576
577 if (skb->protocol == htons(ETH_P_IP))
578 return dccp_v4_do_rcv(sk, skb);
579
Dmitry Mishinfda9ef52006-08-31 15:28:39 -0700580 if (sk_filter(sk, skb))
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800581 goto discard;
582
583 /*
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800584 * socket locking is here for SMP purposes as backlog rcv is currently
585 * called with bh processing disabled.
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800586 */
587
588 /* Do Stevens' IPV6_PKTOPTIONS.
589
590 Yes, guys, it is the only place in our code, where we
591 may make it not affecting IPv4.
592 The rest of code is protocol independent,
593 and I do not like idea to uglify IPv4.
594
595 Actually, all the idea behind IPV6_PKTOPTIONS
596 looks not very well thought. For now we latch
597 options, received in the last packet, enqueued
598 by tcp. Feel free to propose better solution.
YOSHIFUJI Hideakic9eaf172007-02-09 23:24:38 +0900599 --ANK (980728)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800600 */
601 if (np->rxopt.all)
602 opt_skb = skb_clone(skb, GFP_ATOMIC);
603
604 if (sk->sk_state == DCCP_OPEN) { /* Fast path */
605 if (dccp_rcv_established(sk, skb, dccp_hdr(skb), skb->len))
606 goto reset;
Andrii323fbd02017-08-31 08:28:01 +0300607 if (opt_skb)
608 goto ipv6_pktoptions;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800609 return 0;
610 }
611
Gerrit Renkerd83ca5a2006-11-10 16:29:14 -0200612 /*
613 * Step 3: Process LISTEN state
614 * If S.state == LISTEN,
615 * If P.type == Request or P contains a valid Init Cookie option,
616 * (* Must scan the packet's options to check for Init
617 * Cookies. Only Init Cookies are processed here,
618 * however; other options are processed in Step 8. This
619 * scan need only be performed if the endpoint uses Init
620 * Cookies *)
621 * (* Generate a new socket and switch to that socket *)
622 * Set S := new socket for this port pair
623 * S.state = RESPOND
624 * Choose S.ISS (initial seqno) or set from Init Cookies
625 * Initialize S.GAR := S.ISS
626 * Set S.ISR, S.GSR, S.SWL, S.SWH from packet or Init Cookies
627 * Continue with S.state == RESPOND
628 * (* A Response packet will be generated in Step 11 *)
629 * Otherwise,
630 * Generate Reset(No Connection) unless P.type == Reset
631 * Drop packet and return
632 *
633 * NOTE: the check for the packet types is done in
634 * dccp_rcv_state_process
635 */
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800636
637 if (dccp_rcv_state_process(sk, skb, dccp_hdr(skb), skb->len))
638 goto reset;
Andrii323fbd02017-08-31 08:28:01 +0300639 if (opt_skb)
640 goto ipv6_pktoptions;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800641 return 0;
642
643reset:
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800644 dccp_v6_ctl_send_reset(sk, skb);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800645discard:
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800646 if (opt_skb != NULL)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800647 __kfree_skb(opt_skb);
648 kfree_skb(skb);
649 return 0;
Andrii323fbd02017-08-31 08:28:01 +0300650
651/* Handling IPV6_PKTOPTIONS skb the similar
652 * way it's done for net/ipv6/tcp_ipv6.c
653 */
654ipv6_pktoptions:
655 if (!((1 << sk->sk_state) & (DCCPF_CLOSED | DCCPF_LISTEN))) {
656 if (np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo)
657 np->mcast_oif = inet6_iif(opt_skb);
658 if (np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim)
659 np->mcast_hops = ipv6_hdr(opt_skb)->hop_limit;
660 if (np->rxopt.bits.rxflow || np->rxopt.bits.rxtclass)
661 np->rcv_flowinfo = ip6_flowinfo(ipv6_hdr(opt_skb));
662 if (np->repflow)
663 np->flow_label = ip6_flowlabel(ipv6_hdr(opt_skb));
664 if (ipv6_opt_accepted(sk, opt_skb,
665 &DCCP_SKB_CB(opt_skb)->header.h6)) {
666 skb_set_owner_r(opt_skb, sk);
667 memmove(IP6CB(opt_skb),
668 &DCCP_SKB_CB(opt_skb)->header.h6,
669 sizeof(struct inet6_skb_parm));
670 opt_skb = xchg(&np->pktoptions, opt_skb);
671 } else {
672 __kfree_skb(opt_skb);
673 opt_skb = xchg(&np->pktoptions, NULL);
674 }
675 }
676
677 kfree_skb(opt_skb);
678 return 0;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800679}
680
Herbert Xue5bbef22007-10-15 12:50:28 -0700681static int dccp_v6_rcv(struct sk_buff *skb)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800682{
683 const struct dccp_hdr *dh;
Eric Dumazet3b24d852016-04-01 08:52:17 -0700684 bool refcounted;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800685 struct sock *sk;
Gerrit Renker6f4e5ff2006-11-10 17:43:06 -0200686 int min_cov;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800687
Gerrit Renker6f4e5ff2006-11-10 17:43:06 -0200688 /* Step 1: Check header basics */
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800689
690 if (dccp_invalid_packet(skb))
691 goto discard_it;
692
Gerrit Renker6f4e5ff2006-11-10 17:43:06 -0200693 /* Step 1: If header checksum is incorrect, drop packet and return. */
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700694 if (dccp_v6_csum_finish(skb, &ipv6_hdr(skb)->saddr,
695 &ipv6_hdr(skb)->daddr)) {
Gerrit Renker59348b12006-11-20 18:39:23 -0200696 DCCP_WARN("dropped packet with invalid checksum\n");
Gerrit Renker6f4e5ff2006-11-10 17:43:06 -0200697 goto discard_it;
698 }
699
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800700 dh = dccp_hdr(skb);
701
Gerrit Renkerfde20102007-10-24 10:12:09 -0200702 DCCP_SKB_CB(skb)->dccpd_seq = dccp_hdr_seq(dh);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800703 DCCP_SKB_CB(skb)->dccpd_type = dh->dccph_type;
704
705 if (dccp_packet_without_ack(skb))
706 DCCP_SKB_CB(skb)->dccpd_ack_seq = DCCP_PKT_WITHOUT_ACK_SEQ;
707 else
708 DCCP_SKB_CB(skb)->dccpd_ack_seq = dccp_hdr_ack_seq(skb);
709
Eric Dumazet4bdc3d62015-10-13 17:12:54 -0700710lookup:
Craig Galleka5836362016-02-10 11:50:38 -0500711 sk = __inet6_lookup_skb(&dccp_hashinfo, skb, __dccp_hdr_len(dh),
Eric Dumazet870c3152014-10-17 09:17:20 -0700712 dh->dccph_sport, dh->dccph_dport,
David Ahern4297a0e2017-08-07 08:44:21 -0700713 inet6_iif(skb), 0, &refcounted);
Eric Dumazet4bdc3d62015-10-13 17:12:54 -0700714 if (!sk) {
Gerrit Renkerd23c7102006-11-10 11:46:34 -0200715 dccp_pr_debug("failed to look up flow ID in table and "
716 "get corresponding socket\n");
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800717 goto no_dccp_socket;
Gerrit Renkerd23c7102006-11-10 11:46:34 -0200718 }
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800719
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800720 /*
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800721 * Step 2:
Arnaldo Carvalho de Melo8109b022006-12-10 16:01:18 -0200722 * ... or S.state == TIMEWAIT,
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800723 * Generate Reset(No Connection) unless P.type == Reset
724 * Drop packet and return
725 */
Gerrit Renkerd23c7102006-11-10 11:46:34 -0200726 if (sk->sk_state == DCCP_TIME_WAIT) {
727 dccp_pr_debug("sk->sk_state == DCCP_TIME_WAIT: do_time_wait\n");
728 inet_twsk_put(inet_twsk(sk));
729 goto no_dccp_socket;
730 }
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800731
Eric Dumazet079096f2015-10-02 11:43:32 -0700732 if (sk->sk_state == DCCP_NEW_SYN_RECV) {
733 struct request_sock *req = inet_reqsk(sk);
Eric Dumazet77166822016-02-18 05:39:18 -0800734 struct sock *nsk;
Eric Dumazet079096f2015-10-02 11:43:32 -0700735
736 sk = req->rsk_listener;
Eric Dumazet77166822016-02-18 05:39:18 -0800737 if (unlikely(sk->sk_state != DCCP_LISTEN)) {
Eric Dumazetf03f2e12015-10-14 11:16:27 -0700738 inet_csk_reqsk_queue_drop_and_put(sk, req);
Eric Dumazet4bdc3d62015-10-13 17:12:54 -0700739 goto lookup;
740 }
Eric Dumazet77166822016-02-18 05:39:18 -0800741 sock_hold(sk);
Eric Dumazet3b24d852016-04-01 08:52:17 -0700742 refcounted = true;
Eric Dumazet77166822016-02-18 05:39:18 -0800743 nsk = dccp_check_req(sk, skb, req);
Eric Dumazet079096f2015-10-02 11:43:32 -0700744 if (!nsk) {
745 reqsk_put(req);
Eric Dumazet77166822016-02-18 05:39:18 -0800746 goto discard_and_relse;
Eric Dumazet079096f2015-10-02 11:43:32 -0700747 }
748 if (nsk == sk) {
Eric Dumazet079096f2015-10-02 11:43:32 -0700749 reqsk_put(req);
750 } else if (dccp_child_process(sk, nsk, skb)) {
751 dccp_v6_ctl_send_reset(sk, skb);
Eric Dumazet77166822016-02-18 05:39:18 -0800752 goto discard_and_relse;
Eric Dumazet079096f2015-10-02 11:43:32 -0700753 } else {
Eric Dumazet77166822016-02-18 05:39:18 -0800754 sock_put(sk);
Eric Dumazet079096f2015-10-02 11:43:32 -0700755 return 0;
756 }
757 }
Gerrit Renker6f4e5ff2006-11-10 17:43:06 -0200758 /*
759 * RFC 4340, sec. 9.2.1: Minimum Checksum Coverage
Arnaldo Carvalho de Melo8109b022006-12-10 16:01:18 -0200760 * o if MinCsCov = 0, only packets with CsCov = 0 are accepted
761 * o if MinCsCov > 0, also accept packets with CsCov >= MinCsCov
Gerrit Renker6f4e5ff2006-11-10 17:43:06 -0200762 */
763 min_cov = dccp_sk(sk)->dccps_pcrlen;
764 if (dh->dccph_cscov && (min_cov == 0 || dh->dccph_cscov < min_cov)) {
765 dccp_pr_debug("Packet CsCov %d does not satisfy MinCsCov %d\n",
766 dh->dccph_cscov, min_cov);
767 /* FIXME: send Data Dropped option (see also dccp_v4_rcv) */
768 goto discard_and_relse;
769 }
770
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800771 if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb))
772 goto discard_and_relse;
773
Eric Dumazetc3f24cf2016-11-02 17:14:41 -0700774 return __sk_receive_skb(sk, skb, 1, dh->dccph_doff * 4,
775 refcounted) ? -1 : 0;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800776
777no_dccp_socket:
778 if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb))
779 goto discard_it;
780 /*
781 * Step 2:
Arnaldo Carvalho de Melo8109b022006-12-10 16:01:18 -0200782 * If no socket ...
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800783 * Generate Reset(No Connection) unless P.type == Reset
784 * Drop packet and return
785 */
786 if (dh->dccph_type != DCCP_PKT_RESET) {
787 DCCP_SKB_CB(skb)->dccpd_reset_code =
788 DCCP_RESET_CODE_NO_CONNECTION;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800789 dccp_v6_ctl_send_reset(sk, skb);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800790 }
Gerrit Renkerd23c7102006-11-10 11:46:34 -0200791
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800792discard_it:
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800793 kfree_skb(skb);
794 return 0;
795
796discard_and_relse:
Eric Dumazet3b24d852016-04-01 08:52:17 -0700797 if (refcounted)
798 sock_put(sk);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800799 goto discard_it;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800800}
801
Gerrit Renker73c9e022006-11-10 13:01:31 -0200802static int dccp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
803 int addr_len)
804{
805 struct sockaddr_in6 *usin = (struct sockaddr_in6 *)uaddr;
806 struct inet_connection_sock *icsk = inet_csk(sk);
807 struct inet_sock *inet = inet_sk(sk);
808 struct ipv6_pinfo *np = inet6_sk(sk);
809 struct dccp_sock *dp = dccp_sk(sk);
Arnaud Ebalard20c59de2010-06-01 21:35:01 +0000810 struct in6_addr *saddr = NULL, *final_p, final;
Eric Dumazet45f6fad2015-11-29 19:37:57 -0800811 struct ipv6_txoptions *opt;
David S. Miller4c9483b2011-03-12 16:22:43 -0500812 struct flowi6 fl6;
Gerrit Renker73c9e022006-11-10 13:01:31 -0200813 struct dst_entry *dst;
814 int addr_type;
815 int err;
816
817 dp->dccps_role = DCCP_ROLE_CLIENT;
818
819 if (addr_len < SIN6_LEN_RFC2133)
820 return -EINVAL;
821
822 if (usin->sin6_family != AF_INET6)
823 return -EAFNOSUPPORT;
824
David S. Miller4c9483b2011-03-12 16:22:43 -0500825 memset(&fl6, 0, sizeof(fl6));
Gerrit Renker73c9e022006-11-10 13:01:31 -0200826
827 if (np->sndflow) {
David S. Miller4c9483b2011-03-12 16:22:43 -0500828 fl6.flowlabel = usin->sin6_flowinfo & IPV6_FLOWINFO_MASK;
829 IP6_ECN_flow_init(fl6.flowlabel);
830 if (fl6.flowlabel & IPV6_FLOWLABEL_MASK) {
Gerrit Renker73c9e022006-11-10 13:01:31 -0200831 struct ip6_flowlabel *flowlabel;
David S. Miller4c9483b2011-03-12 16:22:43 -0500832 flowlabel = fl6_sock_lookup(sk, fl6.flowlabel);
Willem de Bruijn59c820b2019-07-07 05:34:45 -0400833 if (IS_ERR(flowlabel))
Gerrit Renker73c9e022006-11-10 13:01:31 -0200834 return -EINVAL;
Gerrit Renker73c9e022006-11-10 13:01:31 -0200835 fl6_sock_release(flowlabel);
836 }
837 }
838 /*
839 * connect() to INADDR_ANY means loopback (BSD'ism).
840 */
841 if (ipv6_addr_any(&usin->sin6_addr))
842 usin->sin6_addr.s6_addr[15] = 1;
843
844 addr_type = ipv6_addr_type(&usin->sin6_addr);
845
846 if (addr_type & IPV6_ADDR_MULTICAST)
847 return -ENETUNREACH;
848
849 if (addr_type & IPV6_ADDR_LINKLOCAL) {
850 if (addr_len >= sizeof(struct sockaddr_in6) &&
851 usin->sin6_scope_id) {
852 /* If interface is set while binding, indices
853 * must coincide.
854 */
855 if (sk->sk_bound_dev_if &&
856 sk->sk_bound_dev_if != usin->sin6_scope_id)
857 return -EINVAL;
858
859 sk->sk_bound_dev_if = usin->sin6_scope_id;
860 }
861
862 /* Connect to link-local address requires an interface */
863 if (!sk->sk_bound_dev_if)
864 return -EINVAL;
865 }
866
Eric Dumazetefe42082013-10-03 15:42:29 -0700867 sk->sk_v6_daddr = usin->sin6_addr;
David S. Miller4c9483b2011-03-12 16:22:43 -0500868 np->flow_label = fl6.flowlabel;
Gerrit Renker73c9e022006-11-10 13:01:31 -0200869
870 /*
871 * DCCP over IPv4
872 */
873 if (addr_type == IPV6_ADDR_MAPPED) {
874 u32 exthdrlen = icsk->icsk_ext_hdr_len;
875 struct sockaddr_in sin;
876
877 SOCK_DEBUG(sk, "connect: ipv4 mapped\n");
878
879 if (__ipv6_only_sock(sk))
880 return -ENETUNREACH;
881
882 sin.sin_family = AF_INET;
883 sin.sin_port = usin->sin6_port;
884 sin.sin_addr.s_addr = usin->sin6_addr.s6_addr32[3];
885
886 icsk->icsk_af_ops = &dccp_ipv6_mapped;
887 sk->sk_backlog_rcv = dccp_v4_do_rcv;
888
889 err = dccp_v4_connect(sk, (struct sockaddr *)&sin, sizeof(sin));
890 if (err) {
891 icsk->icsk_ext_hdr_len = exthdrlen;
892 icsk->icsk_af_ops = &dccp_ipv6_af_ops;
893 sk->sk_backlog_rcv = dccp_v6_do_rcv;
894 goto failure;
Gerrit Renker73c9e022006-11-10 13:01:31 -0200895 }
Eric Dumazetd1e559d2015-03-18 14:05:35 -0700896 np->saddr = sk->sk_v6_rcv_saddr;
Gerrit Renker73c9e022006-11-10 13:01:31 -0200897 return err;
898 }
899
Eric Dumazetefe42082013-10-03 15:42:29 -0700900 if (!ipv6_addr_any(&sk->sk_v6_rcv_saddr))
901 saddr = &sk->sk_v6_rcv_saddr;
Gerrit Renker73c9e022006-11-10 13:01:31 -0200902
David S. Miller4c9483b2011-03-12 16:22:43 -0500903 fl6.flowi6_proto = IPPROTO_DCCP;
Eric Dumazetefe42082013-10-03 15:42:29 -0700904 fl6.daddr = sk->sk_v6_daddr;
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +0000905 fl6.saddr = saddr ? *saddr : np->saddr;
David S. Miller4c9483b2011-03-12 16:22:43 -0500906 fl6.flowi6_oif = sk->sk_bound_dev_if;
David S. Miller1958b852011-03-12 16:36:19 -0500907 fl6.fl6_dport = usin->sin6_port;
908 fl6.fl6_sport = inet->inet_sport;
David S. Miller4c9483b2011-03-12 16:22:43 -0500909 security_sk_classify_flow(sk, flowi6_to_flowi(&fl6));
Gerrit Renker73c9e022006-11-10 13:01:31 -0200910
Hannes Frederic Sowa1e1d04e2016-04-05 17:10:15 +0200911 opt = rcu_dereference_protected(np->opt, lockdep_sock_is_held(sk));
Eric Dumazet45f6fad2015-11-29 19:37:57 -0800912 final_p = fl6_update_dst(&fl6, opt, &final);
Gerrit Renker73c9e022006-11-10 13:01:31 -0200913
Steffen Klassert0e0d44a2013-08-28 08:04:14 +0200914 dst = ip6_dst_lookup_flow(sk, &fl6, final_p);
David S. Miller68d0c6d2011-03-01 13:19:07 -0800915 if (IS_ERR(dst)) {
916 err = PTR_ERR(dst);
Gerrit Renker73c9e022006-11-10 13:01:31 -0200917 goto failure;
David S. Miller14e50e52007-05-24 18:17:54 -0700918 }
Gerrit Renker73c9e022006-11-10 13:01:31 -0200919
920 if (saddr == NULL) {
David S. Miller4c9483b2011-03-12 16:22:43 -0500921 saddr = &fl6.saddr;
Eric Dumazetefe42082013-10-03 15:42:29 -0700922 sk->sk_v6_rcv_saddr = *saddr;
Gerrit Renker73c9e022006-11-10 13:01:31 -0200923 }
924
925 /* set the source address */
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +0000926 np->saddr = *saddr;
Eric Dumazetc720c7e82009-10-15 06:30:45 +0000927 inet->inet_rcv_saddr = LOOPBACK4_IPV6;
Gerrit Renker73c9e022006-11-10 13:01:31 -0200928
Eric Dumazet6bd4f352015-12-02 21:53:57 -0800929 ip6_dst_store(sk, dst, NULL, NULL);
Gerrit Renker73c9e022006-11-10 13:01:31 -0200930
931 icsk->icsk_ext_hdr_len = 0;
Eric Dumazet45f6fad2015-11-29 19:37:57 -0800932 if (opt)
933 icsk->icsk_ext_hdr_len = opt->opt_flen + opt->opt_nflen;
Gerrit Renker73c9e022006-11-10 13:01:31 -0200934
Eric Dumazetc720c7e82009-10-15 06:30:45 +0000935 inet->inet_dport = usin->sin6_port;
Gerrit Renker73c9e022006-11-10 13:01:31 -0200936
937 dccp_set_state(sk, DCCP_REQUESTING);
938 err = inet6_hash_connect(&dccp_death_row, sk);
939 if (err)
940 goto late_failure;
Gerrit Renkerd7f73652006-11-13 13:34:38 -0200941
942 dp->dccps_iss = secure_dccpv6_sequence_number(np->saddr.s6_addr32,
Eric Dumazetefe42082013-10-03 15:42:29 -0700943 sk->sk_v6_daddr.s6_addr32,
Eric Dumazetc720c7e82009-10-15 06:30:45 +0000944 inet->inet_sport,
945 inet->inet_dport);
Gerrit Renker73c9e022006-11-10 13:01:31 -0200946 err = dccp_connect(sk);
947 if (err)
948 goto late_failure;
949
950 return 0;
951
952late_failure:
953 dccp_set_state(sk, DCCP_CLOSED);
954 __sk_dst_reset(sk);
955failure:
Eric Dumazetc720c7e82009-10-15 06:30:45 +0000956 inet->inet_dport = 0;
Gerrit Renker73c9e022006-11-10 13:01:31 -0200957 sk->sk_route_caps = 0;
958 return err;
959}
960
Stephen Hemminger3b401a82009-09-01 19:25:04 +0000961static const struct inet_connection_sock_af_ops dccp_ipv6_af_ops = {
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -0800962 .queue_xmit = inet6_csk_xmit,
963 .send_check = dccp_v6_send_check,
964 .rebuild_header = inet6_sk_rebuild_header,
965 .conn_request = dccp_v6_conn_request,
966 .syn_recv_sock = dccp_v6_request_recv_sock,
967 .net_header_len = sizeof(struct ipv6hdr),
968 .setsockopt = ipv6_setsockopt,
969 .getsockopt = ipv6_getsockopt,
970 .addr2sockaddr = inet6_csk_addr2sockaddr,
971 .sockaddr_len = sizeof(struct sockaddr_in6),
Dmitry Mishin3fdadf72006-03-20 22:45:21 -0800972#ifdef CONFIG_COMPAT
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -0800973 .compat_setsockopt = compat_ipv6_setsockopt,
974 .compat_getsockopt = compat_ipv6_getsockopt,
Dmitry Mishin3fdadf72006-03-20 22:45:21 -0800975#endif
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800976};
977
978/*
979 * DCCP over IPv4 via INET6 API
980 */
Stephen Hemminger3b401a82009-09-01 19:25:04 +0000981static const struct inet_connection_sock_af_ops dccp_ipv6_mapped = {
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -0800982 .queue_xmit = ip_queue_xmit,
983 .send_check = dccp_v4_send_check,
984 .rebuild_header = inet_sk_rebuild_header,
985 .conn_request = dccp_v6_conn_request,
986 .syn_recv_sock = dccp_v6_request_recv_sock,
987 .net_header_len = sizeof(struct iphdr),
988 .setsockopt = ipv6_setsockopt,
989 .getsockopt = ipv6_getsockopt,
990 .addr2sockaddr = inet6_csk_addr2sockaddr,
991 .sockaddr_len = sizeof(struct sockaddr_in6),
Dmitry Mishin3fdadf72006-03-20 22:45:21 -0800992#ifdef CONFIG_COMPAT
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -0800993 .compat_setsockopt = compat_ipv6_setsockopt,
994 .compat_getsockopt = compat_ipv6_getsockopt,
Dmitry Mishin3fdadf72006-03-20 22:45:21 -0800995#endif
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800996};
997
998/* NOTE: A lot of things set to zero explicitly by call to
999 * sk_alloc() so need not be done here.
1000 */
1001static int dccp_v6_init_sock(struct sock *sk)
1002{
Arnaldo Carvalho de Melo72478872006-03-20 22:00:37 -08001003 static __u8 dccp_v6_ctl_sock_initialized;
1004 int err = dccp_init_sock(sk, dccp_v6_ctl_sock_initialized);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001005
Arnaldo Carvalho de Melo72478872006-03-20 22:00:37 -08001006 if (err == 0) {
1007 if (unlikely(!dccp_v6_ctl_sock_initialized))
1008 dccp_v6_ctl_sock_initialized = 1;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001009 inet_csk(sk)->icsk_af_ops = &dccp_ipv6_af_ops;
Arnaldo Carvalho de Melo72478872006-03-20 22:00:37 -08001010 }
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001011
1012 return err;
1013}
1014
Brian Haley7d06b2e2008-06-14 17:04:49 -07001015static void dccp_v6_destroy_sock(struct sock *sk)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001016{
Arnaldo Carvalho de Melo3e0fadc2006-03-20 21:23:15 -08001017 dccp_destroy_sock(sk);
Brian Haley7d06b2e2008-06-14 17:04:49 -07001018 inet6_destroy_sock(sk);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001019}
1020
Gerrit Renker73c9e022006-11-10 13:01:31 -02001021static struct timewait_sock_ops dccp6_timewait_sock_ops = {
1022 .twsk_obj_size = sizeof(struct dccp6_timewait_sock),
1023};
1024
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001025static struct proto dccp_v6_prot = {
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001026 .name = "DCCPv6",
1027 .owner = THIS_MODULE,
1028 .close = dccp_close,
1029 .connect = dccp_v6_connect,
1030 .disconnect = dccp_disconnect,
1031 .ioctl = dccp_ioctl,
1032 .init = dccp_v6_init_sock,
1033 .setsockopt = dccp_setsockopt,
1034 .getsockopt = dccp_getsockopt,
1035 .sendmsg = dccp_sendmsg,
1036 .recvmsg = dccp_recvmsg,
1037 .backlog_rcv = dccp_v6_do_rcv,
Craig Gallek496611d2016-02-10 11:50:36 -05001038 .hash = inet6_hash,
Arnaldo Carvalho de Meloab1e0a12008-02-03 04:06:04 -08001039 .unhash = inet_unhash,
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001040 .accept = inet_csk_accept,
Arnaldo Carvalho de Meloab1e0a12008-02-03 04:06:04 -08001041 .get_port = inet_csk_get_port,
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001042 .shutdown = dccp_shutdown,
1043 .destroy = dccp_v6_destroy_sock,
1044 .orphan_count = &dccp_orphan_count,
1045 .max_header = MAX_DCCP_HEADER,
1046 .obj_size = sizeof(struct dccp6_sock),
Paul E. McKenney5f0d5a32017-01-18 02:53:44 -08001047 .slab_flags = SLAB_TYPESAFE_BY_RCU,
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001048 .rsk_prot = &dccp6_request_sock_ops,
1049 .twsk_prot = &dccp6_timewait_sock_ops,
Pavel Emelyanov39d8cda2008-03-22 16:50:58 -07001050 .h.hashinfo = &dccp_hashinfo,
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001051#ifdef CONFIG_COMPAT
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001052 .compat_setsockopt = compat_dccp_setsockopt,
1053 .compat_getsockopt = compat_dccp_getsockopt,
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001054#endif
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001055};
1056
Alexey Dobriyan41135cc2009-09-14 12:22:28 +00001057static const struct inet6_protocol dccp_v6_protocol = {
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -08001058 .handler = dccp_v6_rcv,
1059 .err_handler = dccp_v6_err,
1060 .flags = INET6_PROTO_NOPOLICY | INET6_PROTO_FINAL,
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001061};
1062
Alexey Dobriyan5708e862009-09-14 12:23:23 +00001063static const struct proto_ops inet6_dccp_ops = {
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001064 .family = PF_INET6,
1065 .owner = THIS_MODULE,
1066 .release = inet6_release,
1067 .bind = inet6_bind,
1068 .connect = inet_stream_connect,
1069 .socketpair = sock_no_socketpair,
1070 .accept = inet_accept,
1071 .getname = inet6_getname,
Linus Torvaldsa11e1d42018-06-28 09:43:44 -07001072 .poll = dccp_poll,
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001073 .ioctl = inet6_ioctl,
Arnd Bergmannc7cbdbf2019-04-17 22:51:48 +02001074 .gettstamp = sock_gettstamp,
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001075 .listen = inet_dccp_listen,
1076 .shutdown = inet_shutdown,
1077 .setsockopt = sock_common_setsockopt,
1078 .getsockopt = sock_common_getsockopt,
1079 .sendmsg = inet_sendmsg,
1080 .recvmsg = sock_common_recvmsg,
1081 .mmap = sock_no_mmap,
1082 .sendpage = sock_no_sendpage,
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001083#ifdef CONFIG_COMPAT
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001084 .compat_setsockopt = compat_sock_common_setsockopt,
1085 .compat_getsockopt = compat_sock_common_getsockopt,
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001086#endif
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001087};
1088
1089static struct inet_protosw dccp_v6_protosw = {
1090 .type = SOCK_DCCP,
1091 .protocol = IPPROTO_DCCP,
1092 .prot = &dccp_v6_prot,
1093 .ops = &inet6_dccp_ops,
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -08001094 .flags = INET_PROTOSW_ICSK,
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001095};
1096
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00001097static int __net_init dccp_v6_init_net(struct net *net)
Pavel Emelyanov8231bd22008-04-13 22:32:02 -07001098{
Gerrit Renkerd14a0eb2010-03-14 20:13:19 +00001099 if (dccp_hashinfo.bhash == NULL)
1100 return -ESOCKTNOSUPPORT;
Pavel Emelyanov334527d2008-04-13 22:32:45 -07001101
Gerrit Renkerd14a0eb2010-03-14 20:13:19 +00001102 return inet_ctl_sock_create(&net->dccp.v6_ctl_sk, PF_INET6,
1103 SOCK_DCCP, IPPROTO_DCCP, net);
Pavel Emelyanov8231bd22008-04-13 22:32:02 -07001104}
1105
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00001106static void __net_exit dccp_v6_exit_net(struct net *net)
Pavel Emelyanov8231bd22008-04-13 22:32:02 -07001107{
Pavel Emelyanov334527d2008-04-13 22:32:45 -07001108 inet_ctl_sock_destroy(net->dccp.v6_ctl_sk);
Pavel Emelyanov8231bd22008-04-13 22:32:02 -07001109}
1110
Andrey Ryabininec7cb622017-02-22 12:35:27 +03001111static void __net_exit dccp_v6_exit_batch(struct list_head *net_exit_list)
1112{
1113 inet_twsk_purge(&dccp_hashinfo, AF_INET6);
1114}
1115
Pavel Emelyanov8231bd22008-04-13 22:32:02 -07001116static struct pernet_operations dccp_v6_ops = {
1117 .init = dccp_v6_init_net,
1118 .exit = dccp_v6_exit_net,
Andrey Ryabininec7cb622017-02-22 12:35:27 +03001119 .exit_batch = dccp_v6_exit_batch,
Pavel Emelyanov8231bd22008-04-13 22:32:02 -07001120};
1121
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001122static int __init dccp_v6_init(void)
1123{
1124 int err = proto_register(&dccp_v6_prot, 1);
1125
Xin Longa0f9a4c2017-06-20 15:44:44 +08001126 if (err)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001127 goto out;
1128
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001129 inet6_register_protosw(&dccp_v6_protosw);
Arnaldo Carvalho de Melo72478872006-03-20 22:00:37 -08001130
Pavel Emelyanov8231bd22008-04-13 22:32:02 -07001131 err = register_pernet_subsys(&dccp_v6_ops);
Xin Longa0f9a4c2017-06-20 15:44:44 +08001132 if (err)
Pavel Emelyanov8231bd22008-04-13 22:32:02 -07001133 goto out_destroy_ctl_sock;
Xin Longa0f9a4c2017-06-20 15:44:44 +08001134
1135 err = inet6_add_protocol(&dccp_v6_protocol, IPPROTO_DCCP);
1136 if (err)
1137 goto out_unregister_proto;
1138
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001139out:
1140 return err;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001141out_unregister_proto:
Xin Longa0f9a4c2017-06-20 15:44:44 +08001142 unregister_pernet_subsys(&dccp_v6_ops);
1143out_destroy_ctl_sock:
1144 inet6_unregister_protosw(&dccp_v6_protosw);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001145 proto_unregister(&dccp_v6_prot);
1146 goto out;
1147}
1148
1149static void __exit dccp_v6_exit(void)
1150{
1151 inet6_del_protocol(&dccp_v6_protocol, IPPROTO_DCCP);
Xin Longa0f9a4c2017-06-20 15:44:44 +08001152 unregister_pernet_subsys(&dccp_v6_ops);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001153 inet6_unregister_protosw(&dccp_v6_protosw);
1154 proto_unregister(&dccp_v6_prot);
1155}
1156
1157module_init(dccp_v6_init);
1158module_exit(dccp_v6_exit);
1159
1160/*
1161 * __stringify doesn't likes enums, so use SOCK_DCCP (6) and IPPROTO_DCCP (33)
1162 * values directly, Also cover the case where the protocol is not specified,
1163 * i.e. net-pf-PF_INET6-proto-0-type-SOCK_DCCP
1164 */
Jean Delvare7131c6c2007-10-21 16:45:03 -07001165MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_INET6, 33, 6);
1166MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_INET6, 0, 6);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001167MODULE_LICENSE("GPL");
1168MODULE_AUTHOR("Arnaldo Carvalho de Melo <acme@mandriva.com>");
1169MODULE_DESCRIPTION("DCCPv6 - Datagram Congestion Controlled Protocol");