blob: 6f5304db5a67da0e9d625382b623e41c4adc5f14 [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>
Florian Westphalb98b3302021-04-08 19:45:02 +020030#include <net/netns/generic.h>
Andrii323fbd02017-08-31 08:28:01 +030031#include <net/sock.h>
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -080032
33#include "dccp.h"
34#include "ipv6.h"
Ian McDonald4b79f0a2006-07-23 23:33:28 -070035#include "feat.h"
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -080036
Florian Westphalb98b3302021-04-08 19:45:02 +020037struct dccp_v6_pernet {
38 struct sock *v6_ctl_sk;
39};
40
41static unsigned int dccp_v6_pernet_id __read_mostly;
42
43/* The per-net v6_ctl_sk is used for sending RSTs and ACKs */
Arnaldo Carvalho de Melo72478872006-03-20 22:00:37 -080044
Stephen Hemminger3b401a82009-09-01 19:25:04 +000045static const struct inet_connection_sock_af_ops dccp_ipv6_mapped;
46static const struct inet_connection_sock_af_ops dccp_ipv6_af_ops;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -080047
Gerrit Renker6f4e5ff2006-11-10 17:43:06 -020048/* add pseudo-header to DCCP checksum stored in skb->csum */
Al Viro868c86b2006-11-14 21:35:48 -080049static inline __sum16 dccp_v6_csum_finish(struct sk_buff *skb,
Eric Dumazetb71d1d42011-04-22 04:53:02 +000050 const struct in6_addr *saddr,
51 const struct in6_addr *daddr)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -080052{
Gerrit Renker6f4e5ff2006-11-10 17:43:06 -020053 return csum_ipv6_magic(saddr, daddr, skb->len, IPPROTO_DCCP, skb->csum);
54}
55
Herbert Xubb296242010-04-11 02:15:55 +000056static inline void dccp_v6_send_check(struct sock *sk, struct sk_buff *skb)
Gerrit Renker6f4e5ff2006-11-10 17:43:06 -020057{
58 struct ipv6_pinfo *np = inet6_sk(sk);
59 struct dccp_hdr *dh = dccp_hdr(skb);
60
61 dccp_csum_outgoing(skb);
Eric Dumazetefe42082013-10-03 15:42:29 -070062 dh->dccph_checksum = dccp_v6_csum_finish(skb, &np->saddr, &sk->sk_v6_daddr);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -080063}
64
David S. Miller6e5714e2011-08-03 20:50:44 -070065static inline __u64 dccp_v6_init_sequence(struct sk_buff *skb)
Gerrit Renkerd7f73652006-11-13 13:34:38 -020066{
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -070067 return secure_dccpv6_sequence_number(ipv6_hdr(skb)->daddr.s6_addr32,
68 ipv6_hdr(skb)->saddr.s6_addr32,
Gerrit Renkerd7f73652006-11-13 13:34:38 -020069 dccp_hdr(skb)->dccph_dport,
70 dccp_hdr(skb)->dccph_sport );
71
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -080072}
73
Stefano Brivio32bbd872018-11-08 12:19:21 +010074static int dccp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
Brian Haleyd5fdd6b2009-06-23 04:31:07 -070075 u8 type, u8 code, int offset, __be32 info)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -080076{
Eric Dumazetb71d1d42011-04-22 04:53:02 +000077 const struct ipv6hdr *hdr = (const struct ipv6hdr *)skb->data;
Eric Dumazet1aa9d1a2016-11-02 20:30:48 -070078 const struct dccp_hdr *dh;
Wei Yongjune0bcfb02008-07-26 11:59:10 +010079 struct dccp_sock *dp;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -080080 struct ipv6_pinfo *np;
81 struct sock *sk;
82 int err;
83 __u64 seq;
Pavel Emelyanovca12a1a2008-07-16 20:28:42 -070084 struct net *net = dev_net(skb->dev);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -080085
Eric Dumazet1aa9d1a2016-11-02 20:30:48 -070086 /* Only need dccph_dport & dccph_sport which are the first
87 * 4 bytes in dccp header.
88 * Our caller (icmpv6_notify()) already pulled 8 bytes for us.
89 */
90 BUILD_BUG_ON(offsetofend(struct dccp_hdr, dccph_sport) > 8);
91 BUILD_BUG_ON(offsetofend(struct dccp_hdr, dccph_dport) > 8);
92 dh = (struct dccp_hdr *)(skb->data + offset);
Wei Yongjun860239c2008-07-26 11:59:11 +010093
Eric Dumazet52036a42015-03-22 10:22:25 -070094 sk = __inet6_lookup_established(net, &dccp_hashinfo,
95 &hdr->daddr, dh->dccph_dport,
96 &hdr->saddr, ntohs(dh->dccph_sport),
David Ahern4297a0e2017-08-07 08:44:21 -070097 inet6_iif(skb), 0);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -080098
Eric Dumazet52036a42015-03-22 10:22:25 -070099 if (!sk) {
Eric Dumazeta16292a2016-04-27 16:44:36 -0700100 __ICMP6_INC_STATS(net, __in6_dev_get(skb->dev),
101 ICMP6_MIB_INERRORS);
Stefano Brivio32bbd872018-11-08 12:19:21 +0100102 return -ENOENT;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800103 }
104
105 if (sk->sk_state == DCCP_TIME_WAIT) {
YOSHIFUJI Hideaki9469c7b2006-10-10 19:41:46 -0700106 inet_twsk_put(inet_twsk(sk));
Stefano Brivio32bbd872018-11-08 12:19:21 +0100107 return 0;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800108 }
Eric Dumazet52036a42015-03-22 10:22:25 -0700109 seq = dccp_hdr_seq(dh);
Stefano Brivio32bbd872018-11-08 12:19:21 +0100110 if (sk->sk_state == DCCP_NEW_SYN_RECV) {
111 dccp_req_err(sk, seq);
112 return 0;
113 }
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800114
115 bh_lock_sock(sk);
116 if (sock_owned_by_user(sk))
Eric Dumazet02a1d6e2016-04-27 16:44:39 -0700117 __NET_INC_STATS(net, LINUX_MIB_LOCKDROPPEDICMPS);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800118
119 if (sk->sk_state == DCCP_CLOSED)
120 goto out;
121
Wei Yongjune0bcfb02008-07-26 11:59:10 +0100122 dp = dccp_sk(sk);
Wei Yongjune0bcfb02008-07-26 11:59:10 +0100123 if ((1 << sk->sk_state) & ~(DCCPF_REQUESTING | DCCPF_LISTEN) &&
124 !between48(seq, dp->dccps_awl, dp->dccps_awh)) {
Eric Dumazet02a1d6e2016-04-27 16:44:39 -0700125 __NET_INC_STATS(net, LINUX_MIB_OUTOFWINDOWICMPS);
Wei Yongjune0bcfb02008-07-26 11:59:10 +0100126 goto out;
127 }
128
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800129 np = inet6_sk(sk);
130
David S. Millerec18d9a2012-07-12 00:25:15 -0700131 if (type == NDISC_REDIRECT) {
Jon Maxwell45caeaa2017-03-10 16:40:33 +1100132 if (!sock_owned_by_user(sk)) {
133 struct dst_entry *dst = __sk_dst_check(sk, np->dst_cookie);
David S. Millerec18d9a2012-07-12 00:25:15 -0700134
Jon Maxwell45caeaa2017-03-10 16:40:33 +1100135 if (dst)
136 dst->ops->redirect(dst, sk, skb);
137 }
Duan Jiongbd784a12013-09-18 20:03:27 +0800138 goto out;
David S. Millerec18d9a2012-07-12 00:25:15 -0700139 }
140
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800141 if (type == ICMPV6_PKT_TOOBIG) {
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800142 struct dst_entry *dst = NULL;
143
Hannes Frederic Sowa93b36cf2013-12-15 03:41:14 +0100144 if (!ip6_sk_accept_pmtu(sk))
145 goto out;
146
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800147 if (sock_owned_by_user(sk))
148 goto out;
149 if ((1 << sk->sk_state) & (DCCPF_LISTEN | DCCPF_CLOSED))
150 goto out;
151
David S. Miller35ad9b92012-07-16 03:44:56 -0700152 dst = inet6_csk_update_pmtu(sk, ntohl(info));
153 if (!dst)
154 goto out;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800155
David S. Miller35ad9b92012-07-16 03:44:56 -0700156 if (inet_csk(sk)->icsk_pmtu_cookie > dst_mtu(dst))
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800157 dccp_sync_mss(sk, dst_mtu(dst));
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800158 goto out;
159 }
160
161 icmpv6_err_convert(type, code, &err);
162
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800163 /* Might be for an request_sock */
164 switch (sk->sk_state) {
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800165 case DCCP_REQUESTING:
166 case DCCP_RESPOND: /* Cannot happen.
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800167 It can, it SYNs are crossed. --ANK */
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800168 if (!sock_owned_by_user(sk)) {
Eric Dumazetaa62d762016-04-27 16:44:28 -0700169 __DCCP_INC_STATS(DCCP_MIB_ATTEMPTFAILS);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800170 sk->sk_err = err;
171 /*
172 * Wake people up to see the error
173 * (see connect in sock.c)
174 */
175 sk->sk_error_report(sk);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800176 dccp_done(sk);
177 } else
178 sk->sk_err_soft = err;
179 goto out;
180 }
181
182 if (!sock_owned_by_user(sk) && np->recverr) {
183 sk->sk_err = err;
184 sk->sk_error_report(sk);
185 } else
186 sk->sk_err_soft = err;
187
188out:
189 bh_unlock_sock(sk);
190 sock_put(sk);
Stefano Brivio32bbd872018-11-08 12:19:21 +0100191 return 0;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800192}
193
194
Eric Dumazetea3bea32015-09-25 07:39:23 -0700195static int dccp_v6_send_response(const struct sock *sk, struct request_sock *req)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800196{
Eric Dumazet634fb9792013-10-09 15:21:29 -0700197 struct inet_request_sock *ireq = inet_rsk(req);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800198 struct ipv6_pinfo *np = inet6_sk(sk);
199 struct sk_buff *skb;
Arnaud Ebalard20c59de2010-06-01 21:35:01 +0000200 struct in6_addr *final_p, final;
David S. Miller4c9483b2011-03-12 16:22:43 -0500201 struct flowi6 fl6;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800202 int err = -1;
Denis V. Lunevfd80eb92008-02-29 11:43:03 -0800203 struct dst_entry *dst;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800204
David S. Miller4c9483b2011-03-12 16:22:43 -0500205 memset(&fl6, 0, sizeof(fl6));
206 fl6.flowi6_proto = IPPROTO_DCCP;
Eric Dumazet634fb9792013-10-09 15:21:29 -0700207 fl6.daddr = ireq->ir_v6_rmt_addr;
208 fl6.saddr = ireq->ir_v6_loc_addr;
David S. Miller4c9483b2011-03-12 16:22:43 -0500209 fl6.flowlabel = 0;
Eric Dumazet634fb9792013-10-09 15:21:29 -0700210 fl6.flowi6_oif = ireq->ir_iif;
211 fl6.fl6_dport = ireq->ir_rmt_port;
Eric Dumazetb44084c2013-10-10 00:04:37 -0700212 fl6.fl6_sport = htons(ireq->ir_num);
Paul Moore3df98d72020-09-27 22:38:26 -0400213 security_req_classify_flow(req, flowi6_to_flowi_common(&fl6));
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800214
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800215
Eric Dumazet45f6fad2015-11-29 19:37:57 -0800216 rcu_read_lock();
217 final_p = fl6_update_dst(&fl6, rcu_dereference(np->opt), &final);
218 rcu_read_unlock();
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800219
Sabrina Dubrocac4e85f72019-12-04 15:35:52 +0100220 dst = ip6_dst_lookup_flow(sock_net(sk), sk, &fl6, final_p);
David S. Miller68d0c6d2011-03-01 13:19:07 -0800221 if (IS_ERR(dst)) {
222 err = PTR_ERR(dst);
223 dst = NULL;
Denis V. Lunevfd80eb92008-02-29 11:43:03 -0800224 goto done;
David S. Miller68d0c6d2011-03-01 13:19:07 -0800225 }
Denis V. Lunevfd80eb92008-02-29 11:43:03 -0800226
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800227 skb = dccp_make_response(sk, dst, req);
228 if (skb != NULL) {
229 struct dccp_hdr *dh = dccp_hdr(skb);
Huw Davies56ac42b2016-06-27 15:05:28 -0400230 struct ipv6_txoptions *opt;
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800231
Gerrit Renker6f4e5ff2006-11-10 17:43:06 -0200232 dh->dccph_checksum = dccp_v6_csum_finish(skb,
Eric Dumazet634fb9792013-10-09 15:21:29 -0700233 &ireq->ir_v6_loc_addr,
234 &ireq->ir_v6_rmt_addr);
235 fl6.daddr = ireq->ir_v6_rmt_addr;
Eric Dumazet45f6fad2015-11-29 19:37:57 -0800236 rcu_read_lock();
Huw Davies56ac42b2016-06-27 15:05:28 -0400237 opt = ireq->ipv6_opt;
238 if (!opt)
239 opt = rcu_dereference(np->opt);
Eric Dumazet4f6570d2019-09-24 08:01:14 -0700240 err = ip6_xmit(sk, skb, &fl6, sk->sk_mark, opt, np->tclass,
241 sk->sk_priority);
Eric Dumazet45f6fad2015-11-29 19:37:57 -0800242 rcu_read_unlock();
Gerrit Renkerb9df3cb2006-11-14 11:21:36 -0200243 err = net_xmit_eval(err);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800244 }
245
246done:
David S. Miller0cbd7822006-01-31 17:53:37 -0800247 dst_release(dst);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800248 return err;
249}
250
251static void dccp_v6_reqsk_destructor(struct request_sock *req)
252{
Gerrit Renkerd99a7bd2008-11-04 23:56:30 -0800253 dccp_feat_list_purge(&dccp_rsk(req)->dreq_featneg);
Huw Davies56ac42b2016-06-27 15:05:28 -0400254 kfree(inet_rsk(req)->ipv6_opt);
Eric Dumazet634fb9792013-10-09 15:21:29 -0700255 kfree_skb(inet_rsk(req)->pktopts);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800256}
257
Eric Dumazeta00e7442015-09-29 07:42:39 -0700258static void dccp_v6_ctl_send_reset(const struct sock *sk, struct sk_buff *rxskb)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800259{
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000260 const struct ipv6hdr *rxip6h;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800261 struct sk_buff *skb;
David S. Miller4c9483b2011-03-12 16:22:43 -0500262 struct flowi6 fl6;
Eric Dumazetadf30902009-06-02 05:19:30 +0000263 struct net *net = dev_net(skb_dst(rxskb)->dev);
Florian Westphalb98b3302021-04-08 19:45:02 +0200264 struct dccp_v6_pernet *pn;
265 struct sock *ctl_sk;
Eric Dumazetadf30902009-06-02 05:19:30 +0000266 struct dst_entry *dst;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800267
Gerrit Renkere356d372007-09-26 14:35:19 -0300268 if (dccp_hdr(rxskb)->dccph_type == DCCP_PKT_RESET)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800269 return;
270
271 if (!ipv6_unicast_destination(rxskb))
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800272 return;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800273
Florian Westphalb98b3302021-04-08 19:45:02 +0200274 pn = net_generic(net, dccp_v6_pernet_id);
275 ctl_sk = pn->v6_ctl_sk;
Pavel Emelyanov02047742008-04-13 22:32:25 -0700276 skb = dccp_ctl_make_reset(ctl_sk, rxskb);
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800277 if (skb == NULL)
Arnaldo Carvalho de Melo8109b022006-12-10 16:01:18 -0200278 return;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800279
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700280 rxip6h = ipv6_hdr(rxskb);
Gerrit Renkere356d372007-09-26 14:35:19 -0300281 dccp_hdr(skb)->dccph_checksum = dccp_v6_csum_finish(skb, &rxip6h->saddr,
282 &rxip6h->daddr);
Gerrit Renker6f4e5ff2006-11-10 17:43:06 -0200283
David S. Miller4c9483b2011-03-12 16:22:43 -0500284 memset(&fl6, 0, sizeof(fl6));
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +0000285 fl6.daddr = rxip6h->saddr;
286 fl6.saddr = rxip6h->daddr;
Gerrit Renker6f4e5ff2006-11-10 17:43:06 -0200287
David S. Miller4c9483b2011-03-12 16:22:43 -0500288 fl6.flowi6_proto = IPPROTO_DCCP;
289 fl6.flowi6_oif = inet6_iif(rxskb);
David S. Miller1958b852011-03-12 16:36:19 -0500290 fl6.fl6_dport = dccp_hdr(skb)->dccph_dport;
291 fl6.fl6_sport = dccp_hdr(skb)->dccph_sport;
Paul Moore3df98d72020-09-27 22:38:26 -0400292 security_skb_classify_flow(rxskb, flowi6_to_flowi_common(&fl6));
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800293
294 /* sk = NULL, but it is safe for now. RST socket required. */
Sabrina Dubrocac4e85f72019-12-04 15:35:52 +0100295 dst = ip6_dst_lookup_flow(sock_net(ctl_sk), ctl_sk, &fl6, NULL);
David S. Miller68d0c6d2011-03-01 13:19:07 -0800296 if (!IS_ERR(dst)) {
297 skb_dst_set(skb, dst);
Eric Dumazet4f6570d2019-09-24 08:01:14 -0700298 ip6_xmit(ctl_sk, skb, &fl6, 0, NULL, 0, 0);
Eric Dumazet7309f882016-04-29 14:16:49 -0700299 DCCP_INC_STATS(DCCP_MIB_OUTSEGS);
300 DCCP_INC_STATS(DCCP_MIB_OUTRSTS);
David S. Miller68d0c6d2011-03-01 13:19:07 -0800301 return;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800302 }
303
304 kfree_skb(skb);
305}
306
Gerrit Renker73c9e022006-11-10 13:01:31 -0200307static struct request_sock_ops dccp6_request_sock_ops = {
308 .family = AF_INET6,
309 .obj_size = sizeof(struct dccp6_request_sock),
310 .rtx_syn_ack = dccp_v6_send_response,
311 .send_ack = dccp_reqsk_send_ack,
312 .destructor = dccp_v6_reqsk_destructor,
313 .send_reset = dccp_v6_ctl_send_reset,
Eric Dumazetc72e1182012-04-12 22:16:05 +0000314 .syn_ack_timeout = dccp_syn_ack_timeout,
Gerrit Renker73c9e022006-11-10 13:01:31 -0200315};
316
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800317static int dccp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
318{
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800319 struct request_sock *req;
320 struct dccp_request_sock *dreq;
Eric Dumazet634fb9792013-10-09 15:21:29 -0700321 struct inet_request_sock *ireq;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800322 struct ipv6_pinfo *np = inet6_sk(sk);
Arnaldo Carvalho de Melo8109b022006-12-10 16:01:18 -0200323 const __be32 service = dccp_hdr_request(skb)->dccph_req_service;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800324 struct dccp_skb_cb *dcb = DCCP_SKB_CB(skb);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800325
326 if (skb->protocol == htons(ETH_P_IP))
327 return dccp_v4_conn_request(sk, skb);
328
329 if (!ipv6_unicast_destination(skb))
Gerrit Renker4a5409a2007-10-04 14:52:28 -0700330 return 0; /* discard, don't send a reset here */
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800331
Jakub Kicinskidcc32f4f2021-03-17 09:55:15 -0700332 if (ipv6_addr_v4mapped(&ipv6_hdr(skb)->saddr)) {
333 __IP6_INC_STATS(sock_net(sk), NULL, IPSTATS_MIB_INHDRERRORS);
334 return 0;
335 }
336
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800337 if (dccp_bad_service_code(sk, service)) {
Gerrit Renker4a5409a2007-10-04 14:52:28 -0700338 dcb->dccpd_reset_code = DCCP_RESET_CODE_BAD_SERVICE_CODE;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800339 goto drop;
Arnaldo Carvalho de Melo8109b022006-12-10 16:01:18 -0200340 }
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800341 /*
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800342 * There are no SYN attacks on IPv6, yet...
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800343 */
Gerrit Renker4a5409a2007-10-04 14:52:28 -0700344 dcb->dccpd_reset_code = DCCP_RESET_CODE_TOO_BUSY;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800345 if (inet_csk_reqsk_queue_is_full(sk))
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800346 goto drop;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800347
Eric Dumazet5ea8ea22016-10-26 09:27:57 -0700348 if (sk_acceptq_is_full(sk))
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800349 goto drop;
350
Eric Dumazeta1a53442015-10-04 21:08:11 -0700351 req = inet_reqsk_alloc(&dccp6_request_sock_ops, sk, true);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800352 if (req == NULL)
353 goto drop;
354
Gerrit Renkerac757732008-11-04 23:55:49 -0800355 if (dccp_reqsk_init(req, dccp_sk(sk), skb))
356 goto drop_and_free;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800357
Gerrit Renker8b819412007-12-13 12:29:24 -0200358 dreq = dccp_rsk(req);
359 if (dccp_parse_options(sk, dreq, skb))
360 goto drop_and_free;
361
Venkat Yekkirala4237c752006-07-24 23:32:50 -0700362 if (security_inet_conn_request(sk, skb, req))
363 goto drop_and_free;
364
Eric Dumazet634fb9792013-10-09 15:21:29 -0700365 ireq = inet_rsk(req);
366 ireq->ir_v6_rmt_addr = ipv6_hdr(skb)->saddr;
367 ireq->ir_v6_loc_addr = ipv6_hdr(skb)->daddr;
Eric Dumazet3f66b082015-03-12 16:44:10 -0700368 ireq->ireq_family = AF_INET6;
Eric Dumazetb855ff82018-04-07 13:42:41 -0700369 ireq->ir_mark = inet_request_mark(sk, skb);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800370
Eric Dumazeta2247722014-09-27 09:50:56 -0700371 if (ipv6_opt_accepted(sk, skb, IP6CB(skb)) ||
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800372 np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo ||
373 np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim) {
Reshetova, Elena63354792017-06-30 13:07:58 +0300374 refcount_inc(&skb->users);
Eric Dumazet634fb9792013-10-09 15:21:29 -0700375 ireq->pktopts = skb;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800376 }
Eric Dumazet634fb9792013-10-09 15:21:29 -0700377 ireq->ir_iif = sk->sk_bound_dev_if;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800378
379 /* So that link locals have meaning */
380 if (!sk->sk_bound_dev_if &&
Eric Dumazet634fb9792013-10-09 15:21:29 -0700381 ipv6_addr_type(&ireq->ir_v6_rmt_addr) & IPV6_ADDR_LINKLOCAL)
382 ireq->ir_iif = inet6_iif(skb);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800383
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800384 /*
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800385 * Step 3: Process LISTEN state
386 *
Gerrit Renkerd83ca5a2006-11-10 16:29:14 -0200387 * Set S.ISR, S.GSR, S.SWL, S.SWH from packet or Init Cookie
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800388 *
Samuel Jerof541fb72012-02-26 18:22:02 -0700389 * Setting S.SWL/S.SWH to is deferred to dccp_create_openreq_child().
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800390 */
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800391 dreq->dreq_isr = dcb->dccpd_seq;
Samuel Jerof541fb72012-02-26 18:22:02 -0700392 dreq->dreq_gsr = dreq->dreq_isr;
Gerrit Renker865e9022006-11-13 13:31:50 -0200393 dreq->dreq_iss = dccp_v6_init_sequence(skb);
Samuel Jerof541fb72012-02-26 18:22:02 -0700394 dreq->dreq_gss = dreq->dreq_iss;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800395 dreq->dreq_service = service;
396
Christoph Paasch1a2c6182013-03-17 08:23:34 +0000397 if (dccp_v6_send_response(sk, req))
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800398 goto drop_and_free;
399
Eric Dumazet079096f2015-10-02 11:43:32 -0700400 inet_csk_reqsk_queue_hash_add(sk, req, DCCP_TIMEOUT_INIT);
Xin Long0c2232b2017-07-26 14:19:09 +0800401 reqsk_put(req);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800402 return 0;
403
404drop_and_free:
405 reqsk_free(req);
406drop:
Eric Dumazetaa62d762016-04-27 16:44:28 -0700407 __DCCP_INC_STATS(DCCP_MIB_ATTEMPTFAILS);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800408 return -1;
409}
410
Eric Dumazet0c271712015-09-29 07:42:48 -0700411static struct sock *dccp_v6_request_recv_sock(const struct sock *sk,
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800412 struct sk_buff *skb,
413 struct request_sock *req,
Eric Dumazet5e0724d2015-10-22 08:20:46 -0700414 struct dst_entry *dst,
415 struct request_sock *req_unhash,
416 bool *own_req)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800417{
Eric Dumazet634fb9792013-10-09 15:21:29 -0700418 struct inet_request_sock *ireq = inet_rsk(req);
Eric Dumazet0c271712015-09-29 07:42:48 -0700419 struct ipv6_pinfo *newnp;
420 const struct ipv6_pinfo *np = inet6_sk(sk);
Eric Dumazet45f6fad2015-11-29 19:37:57 -0800421 struct ipv6_txoptions *opt;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800422 struct inet_sock *newinet;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800423 struct dccp6_sock *newdp6;
424 struct sock *newsk;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800425
426 if (skb->protocol == htons(ETH_P_IP)) {
427 /*
428 * v6 mapped
429 */
Eric Dumazet5e0724d2015-10-22 08:20:46 -0700430 newsk = dccp_v4_request_recv_sock(sk, skb, req, dst,
431 req_unhash, own_req);
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800432 if (newsk == NULL)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800433 return NULL;
434
435 newdp6 = (struct dccp6_sock *)newsk;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800436 newinet = inet_sk(newsk);
437 newinet->pinet6 = &newdp6->inet6;
438 newnp = inet6_sk(newsk);
439
440 memcpy(newnp, np, sizeof(struct ipv6_pinfo));
441
Eric Dumazetd1e559d2015-03-18 14:05:35 -0700442 newnp->saddr = newsk->sk_v6_rcv_saddr;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800443
444 inet_csk(newsk)->icsk_af_ops = &dccp_ipv6_mapped;
445 newsk->sk_backlog_rcv = dccp_v4_do_rcv;
446 newnp->pktoptions = NULL;
447 newnp->opt = NULL;
WANG Cong83eadda2017-05-09 16:59:54 -0700448 newnp->ipv6_mc_list = NULL;
449 newnp->ipv6_ac_list = NULL;
450 newnp->ipv6_fl_list = NULL;
Eric Dumazete0aa6772019-03-19 05:46:18 -0700451 newnp->mcast_oif = inet_iif(skb);
452 newnp->mcast_hops = ip_hdr(skb)->ttl;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800453
454 /*
455 * No need to charge this sock to the relevant IPv6 refcnt debug socks count
456 * here, dccp_create_openreq_child now does this for us, see the comment in
457 * that function for the gory details. -acme
458 */
459
460 /* It is tricky place. Until this moment IPv4 tcp
461 worked with IPv6 icsk.icsk_af_ops.
462 Sync it now.
463 */
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -0800464 dccp_sync_mss(newsk, inet_csk(newsk)->icsk_pmtu_cookie);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800465
466 return newsk;
467 }
468
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800469
470 if (sk_acceptq_is_full(sk))
471 goto out_overflow;
472
Eric Dumazetf76b33c2015-09-29 07:42:42 -0700473 if (!dst) {
David S. Miller4c9483b2011-03-12 16:22:43 -0500474 struct flowi6 fl6;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800475
Eric Dumazetf76b33c2015-09-29 07:42:42 -0700476 dst = inet6_csk_route_req(sk, &fl6, req, IPPROTO_DCCP);
477 if (!dst)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800478 goto out;
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800479 }
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800480
481 newsk = dccp_create_openreq_child(sk, req, skb);
482 if (newsk == NULL)
Balazs Scheidler093d2822010-10-21 13:06:43 +0200483 goto out_nonewsk;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800484
485 /*
486 * No need to charge this sock to the relevant IPv6 refcnt debug socks
487 * count here, dccp_create_openreq_child now does this for us, see the
488 * comment in that function for the gory details. -acme
489 */
490
Eric Dumazet6bd4f352015-12-02 21:53:57 -0800491 ip6_dst_store(newsk, dst, NULL, NULL);
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800492 newsk->sk_route_caps = dst->dev->features & ~(NETIF_F_IP_CSUM |
493 NETIF_F_TSO);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800494 newdp6 = (struct dccp6_sock *)newsk;
495 newinet = inet_sk(newsk);
496 newinet->pinet6 = &newdp6->inet6;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800497 newnp = inet6_sk(newsk);
498
499 memcpy(newnp, np, sizeof(struct ipv6_pinfo));
500
Eric Dumazet634fb9792013-10-09 15:21:29 -0700501 newsk->sk_v6_daddr = ireq->ir_v6_rmt_addr;
502 newnp->saddr = ireq->ir_v6_loc_addr;
503 newsk->sk_v6_rcv_saddr = ireq->ir_v6_loc_addr;
504 newsk->sk_bound_dev_if = ireq->ir_iif;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800505
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800506 /* Now IPv6 options...
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800507
508 First: no IPv4 options.
509 */
Eric Dumazetf6d8bd02011-04-21 09:45:37 +0000510 newinet->inet_opt = NULL;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800511
512 /* Clone RX bits */
513 newnp->rxopt.all = np->rxopt.all;
514
WANG Cong83eadda2017-05-09 16:59:54 -0700515 newnp->ipv6_mc_list = NULL;
516 newnp->ipv6_ac_list = NULL;
517 newnp->ipv6_fl_list = NULL;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800518 newnp->pktoptions = NULL;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800519 newnp->opt = NULL;
520 newnp->mcast_oif = inet6_iif(skb);
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700521 newnp->mcast_hops = ipv6_hdr(skb)->hop_limit;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800522
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800523 /*
524 * Clone native IPv6 options from listening socket (if any)
525 *
526 * Yes, keeping reference count would be much more clever, but we make
527 * one more one thing there: reattach optmem to newsk.
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800528 */
Huw Davies56ac42b2016-06-27 15:05:28 -0400529 opt = ireq->ipv6_opt;
530 if (!opt)
531 opt = rcu_dereference(np->opt);
Eric Dumazet45f6fad2015-11-29 19:37:57 -0800532 if (opt) {
533 opt = ipv6_dup_options(newsk, opt);
534 RCU_INIT_POINTER(newnp->opt, opt);
535 }
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -0800536 inet_csk(newsk)->icsk_ext_hdr_len = 0;
Eric Dumazet45f6fad2015-11-29 19:37:57 -0800537 if (opt)
538 inet_csk(newsk)->icsk_ext_hdr_len = opt->opt_nflen +
539 opt->opt_flen;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800540
541 dccp_sync_mss(newsk, dst_mtu(dst));
542
Eric Dumazetc720c7e82009-10-15 06:30:45 +0000543 newinet->inet_daddr = newinet->inet_saddr = LOOPBACK4_IPV6;
544 newinet->inet_rcv_saddr = LOOPBACK4_IPV6;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800545
Balazs Scheidler093d2822010-10-21 13:06:43 +0200546 if (__inet_inherit_port(sk, newsk) < 0) {
Christoph Paasche337e242012-12-14 04:07:58 +0000547 inet_csk_prepare_forced_close(newsk);
548 dccp_done(newsk);
Balazs Scheidler093d2822010-10-21 13:06:43 +0200549 goto out;
550 }
Ricardo Dias01770a12020-11-20 11:11:33 +0000551 *own_req = inet_ehash_nolisten(newsk, req_to_sk(req_unhash), NULL);
Eric Dumazetce105002015-10-30 09:46:12 -0700552 /* Clone pktoptions received with SYN, if we own the req */
553 if (*own_req && ireq->pktopts) {
554 newnp->pktoptions = skb_clone(ireq->pktopts, GFP_ATOMIC);
555 consume_skb(ireq->pktopts);
556 ireq->pktopts = NULL;
557 if (newnp->pktoptions)
558 skb_set_owner_r(newnp->pktoptions, newsk);
559 }
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800560
561 return newsk;
562
563out_overflow:
Eric Dumazet02a1d6e2016-04-27 16:44:39 -0700564 __NET_INC_STATS(sock_net(sk), LINUX_MIB_LISTENOVERFLOWS);
Balazs Scheidler093d2822010-10-21 13:06:43 +0200565out_nonewsk:
566 dst_release(dst);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800567out:
Eric Dumazet02a1d6e2016-04-27 16:44:39 -0700568 __NET_INC_STATS(sock_net(sk), LINUX_MIB_LISTENDROPS);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800569 return NULL;
570}
571
572/* The socket must have it's spinlock held when we get
573 * here.
574 *
575 * We have a potential double-lock case here, so even when
576 * doing backlog processing we use the BH locking scheme.
577 * This is because we cannot sleep with the original spinlock
578 * held.
579 */
580static int dccp_v6_do_rcv(struct sock *sk, struct sk_buff *skb)
581{
582 struct ipv6_pinfo *np = inet6_sk(sk);
583 struct sk_buff *opt_skb = NULL;
584
585 /* Imagine: socket is IPv6. IPv4 packet arrives,
586 goes to IPv4 receive handler and backlogged.
587 From backlog it always goes here. Kerboom...
588 Fortunately, dccp_rcv_established and rcv_established
589 handle them correctly, but it is not case with
590 dccp_v6_hnd_req and dccp_v6_ctl_send_reset(). --ANK
591 */
592
593 if (skb->protocol == htons(ETH_P_IP))
594 return dccp_v4_do_rcv(sk, skb);
595
Dmitry Mishinfda9ef52006-08-31 15:28:39 -0700596 if (sk_filter(sk, skb))
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800597 goto discard;
598
599 /*
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800600 * socket locking is here for SMP purposes as backlog rcv is currently
601 * called with bh processing disabled.
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800602 */
603
604 /* Do Stevens' IPV6_PKTOPTIONS.
605
606 Yes, guys, it is the only place in our code, where we
607 may make it not affecting IPv4.
608 The rest of code is protocol independent,
609 and I do not like idea to uglify IPv4.
610
611 Actually, all the idea behind IPV6_PKTOPTIONS
612 looks not very well thought. For now we latch
613 options, received in the last packet, enqueued
614 by tcp. Feel free to propose better solution.
YOSHIFUJI Hideakic9eaf172007-02-09 23:24:38 +0900615 --ANK (980728)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800616 */
617 if (np->rxopt.all)
618 opt_skb = skb_clone(skb, GFP_ATOMIC);
619
620 if (sk->sk_state == DCCP_OPEN) { /* Fast path */
621 if (dccp_rcv_established(sk, skb, dccp_hdr(skb), skb->len))
622 goto reset;
Andrii323fbd02017-08-31 08:28:01 +0300623 if (opt_skb)
624 goto ipv6_pktoptions;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800625 return 0;
626 }
627
Gerrit Renkerd83ca5a2006-11-10 16:29:14 -0200628 /*
629 * Step 3: Process LISTEN state
630 * If S.state == LISTEN,
631 * If P.type == Request or P contains a valid Init Cookie option,
632 * (* Must scan the packet's options to check for Init
633 * Cookies. Only Init Cookies are processed here,
634 * however; other options are processed in Step 8. This
635 * scan need only be performed if the endpoint uses Init
636 * Cookies *)
637 * (* Generate a new socket and switch to that socket *)
638 * Set S := new socket for this port pair
639 * S.state = RESPOND
640 * Choose S.ISS (initial seqno) or set from Init Cookies
641 * Initialize S.GAR := S.ISS
642 * Set S.ISR, S.GSR, S.SWL, S.SWH from packet or Init Cookies
643 * Continue with S.state == RESPOND
644 * (* A Response packet will be generated in Step 11 *)
645 * Otherwise,
646 * Generate Reset(No Connection) unless P.type == Reset
647 * Drop packet and return
648 *
649 * NOTE: the check for the packet types is done in
650 * dccp_rcv_state_process
651 */
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800652
653 if (dccp_rcv_state_process(sk, skb, dccp_hdr(skb), skb->len))
654 goto reset;
Andrii323fbd02017-08-31 08:28:01 +0300655 if (opt_skb)
656 goto ipv6_pktoptions;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800657 return 0;
658
659reset:
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800660 dccp_v6_ctl_send_reset(sk, skb);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800661discard:
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800662 if (opt_skb != NULL)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800663 __kfree_skb(opt_skb);
664 kfree_skb(skb);
665 return 0;
Andrii323fbd02017-08-31 08:28:01 +0300666
667/* Handling IPV6_PKTOPTIONS skb the similar
668 * way it's done for net/ipv6/tcp_ipv6.c
669 */
670ipv6_pktoptions:
671 if (!((1 << sk->sk_state) & (DCCPF_CLOSED | DCCPF_LISTEN))) {
672 if (np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo)
673 np->mcast_oif = inet6_iif(opt_skb);
674 if (np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim)
675 np->mcast_hops = ipv6_hdr(opt_skb)->hop_limit;
676 if (np->rxopt.bits.rxflow || np->rxopt.bits.rxtclass)
677 np->rcv_flowinfo = ip6_flowinfo(ipv6_hdr(opt_skb));
678 if (np->repflow)
679 np->flow_label = ip6_flowlabel(ipv6_hdr(opt_skb));
680 if (ipv6_opt_accepted(sk, opt_skb,
681 &DCCP_SKB_CB(opt_skb)->header.h6)) {
682 skb_set_owner_r(opt_skb, sk);
683 memmove(IP6CB(opt_skb),
684 &DCCP_SKB_CB(opt_skb)->header.h6,
685 sizeof(struct inet6_skb_parm));
686 opt_skb = xchg(&np->pktoptions, opt_skb);
687 } else {
688 __kfree_skb(opt_skb);
689 opt_skb = xchg(&np->pktoptions, NULL);
690 }
691 }
692
693 kfree_skb(opt_skb);
694 return 0;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800695}
696
Herbert Xue5bbef22007-10-15 12:50:28 -0700697static int dccp_v6_rcv(struct sk_buff *skb)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800698{
699 const struct dccp_hdr *dh;
Eric Dumazet3b24d852016-04-01 08:52:17 -0700700 bool refcounted;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800701 struct sock *sk;
Gerrit Renker6f4e5ff2006-11-10 17:43:06 -0200702 int min_cov;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800703
Gerrit Renker6f4e5ff2006-11-10 17:43:06 -0200704 /* Step 1: Check header basics */
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800705
706 if (dccp_invalid_packet(skb))
707 goto discard_it;
708
Gerrit Renker6f4e5ff2006-11-10 17:43:06 -0200709 /* Step 1: If header checksum is incorrect, drop packet and return. */
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700710 if (dccp_v6_csum_finish(skb, &ipv6_hdr(skb)->saddr,
711 &ipv6_hdr(skb)->daddr)) {
Gerrit Renker59348b12006-11-20 18:39:23 -0200712 DCCP_WARN("dropped packet with invalid checksum\n");
Gerrit Renker6f4e5ff2006-11-10 17:43:06 -0200713 goto discard_it;
714 }
715
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800716 dh = dccp_hdr(skb);
717
Gerrit Renkerfde20102007-10-24 10:12:09 -0200718 DCCP_SKB_CB(skb)->dccpd_seq = dccp_hdr_seq(dh);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800719 DCCP_SKB_CB(skb)->dccpd_type = dh->dccph_type;
720
721 if (dccp_packet_without_ack(skb))
722 DCCP_SKB_CB(skb)->dccpd_ack_seq = DCCP_PKT_WITHOUT_ACK_SEQ;
723 else
724 DCCP_SKB_CB(skb)->dccpd_ack_seq = dccp_hdr_ack_seq(skb);
725
Eric Dumazet4bdc3d62015-10-13 17:12:54 -0700726lookup:
Craig Galleka5836362016-02-10 11:50:38 -0500727 sk = __inet6_lookup_skb(&dccp_hashinfo, skb, __dccp_hdr_len(dh),
Eric Dumazet870c3152014-10-17 09:17:20 -0700728 dh->dccph_sport, dh->dccph_dport,
David Ahern4297a0e2017-08-07 08:44:21 -0700729 inet6_iif(skb), 0, &refcounted);
Eric Dumazet4bdc3d62015-10-13 17:12:54 -0700730 if (!sk) {
Gerrit Renkerd23c7102006-11-10 11:46:34 -0200731 dccp_pr_debug("failed to look up flow ID in table and "
732 "get corresponding socket\n");
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800733 goto no_dccp_socket;
Gerrit Renkerd23c7102006-11-10 11:46:34 -0200734 }
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800735
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800736 /*
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800737 * Step 2:
Arnaldo Carvalho de Melo8109b022006-12-10 16:01:18 -0200738 * ... or S.state == TIMEWAIT,
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800739 * Generate Reset(No Connection) unless P.type == Reset
740 * Drop packet and return
741 */
Gerrit Renkerd23c7102006-11-10 11:46:34 -0200742 if (sk->sk_state == DCCP_TIME_WAIT) {
743 dccp_pr_debug("sk->sk_state == DCCP_TIME_WAIT: do_time_wait\n");
744 inet_twsk_put(inet_twsk(sk));
745 goto no_dccp_socket;
746 }
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800747
Eric Dumazet079096f2015-10-02 11:43:32 -0700748 if (sk->sk_state == DCCP_NEW_SYN_RECV) {
749 struct request_sock *req = inet_reqsk(sk);
Eric Dumazet77166822016-02-18 05:39:18 -0800750 struct sock *nsk;
Eric Dumazet079096f2015-10-02 11:43:32 -0700751
752 sk = req->rsk_listener;
Eric Dumazet77166822016-02-18 05:39:18 -0800753 if (unlikely(sk->sk_state != DCCP_LISTEN)) {
Eric Dumazetf03f2e12015-10-14 11:16:27 -0700754 inet_csk_reqsk_queue_drop_and_put(sk, req);
Eric Dumazet4bdc3d62015-10-13 17:12:54 -0700755 goto lookup;
756 }
Eric Dumazet77166822016-02-18 05:39:18 -0800757 sock_hold(sk);
Eric Dumazet3b24d852016-04-01 08:52:17 -0700758 refcounted = true;
Eric Dumazet77166822016-02-18 05:39:18 -0800759 nsk = dccp_check_req(sk, skb, req);
Eric Dumazet079096f2015-10-02 11:43:32 -0700760 if (!nsk) {
761 reqsk_put(req);
Eric Dumazet77166822016-02-18 05:39:18 -0800762 goto discard_and_relse;
Eric Dumazet079096f2015-10-02 11:43:32 -0700763 }
764 if (nsk == sk) {
Eric Dumazet079096f2015-10-02 11:43:32 -0700765 reqsk_put(req);
766 } else if (dccp_child_process(sk, nsk, skb)) {
767 dccp_v6_ctl_send_reset(sk, skb);
Eric Dumazet77166822016-02-18 05:39:18 -0800768 goto discard_and_relse;
Eric Dumazet079096f2015-10-02 11:43:32 -0700769 } else {
Eric Dumazet77166822016-02-18 05:39:18 -0800770 sock_put(sk);
Eric Dumazet079096f2015-10-02 11:43:32 -0700771 return 0;
772 }
773 }
Gerrit Renker6f4e5ff2006-11-10 17:43:06 -0200774 /*
775 * RFC 4340, sec. 9.2.1: Minimum Checksum Coverage
Arnaldo Carvalho de Melo8109b022006-12-10 16:01:18 -0200776 * o if MinCsCov = 0, only packets with CsCov = 0 are accepted
777 * o if MinCsCov > 0, also accept packets with CsCov >= MinCsCov
Gerrit Renker6f4e5ff2006-11-10 17:43:06 -0200778 */
779 min_cov = dccp_sk(sk)->dccps_pcrlen;
780 if (dh->dccph_cscov && (min_cov == 0 || dh->dccph_cscov < min_cov)) {
781 dccp_pr_debug("Packet CsCov %d does not satisfy MinCsCov %d\n",
782 dh->dccph_cscov, min_cov);
783 /* FIXME: send Data Dropped option (see also dccp_v4_rcv) */
784 goto discard_and_relse;
785 }
786
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800787 if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb))
788 goto discard_and_relse;
789
Eric Dumazetc3f24cf2016-11-02 17:14:41 -0700790 return __sk_receive_skb(sk, skb, 1, dh->dccph_doff * 4,
791 refcounted) ? -1 : 0;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800792
793no_dccp_socket:
794 if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb))
795 goto discard_it;
796 /*
797 * Step 2:
Arnaldo Carvalho de Melo8109b022006-12-10 16:01:18 -0200798 * If no socket ...
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800799 * Generate Reset(No Connection) unless P.type == Reset
800 * Drop packet and return
801 */
802 if (dh->dccph_type != DCCP_PKT_RESET) {
803 DCCP_SKB_CB(skb)->dccpd_reset_code =
804 DCCP_RESET_CODE_NO_CONNECTION;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800805 dccp_v6_ctl_send_reset(sk, skb);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800806 }
Gerrit Renkerd23c7102006-11-10 11:46:34 -0200807
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800808discard_it:
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800809 kfree_skb(skb);
810 return 0;
811
812discard_and_relse:
Eric Dumazet3b24d852016-04-01 08:52:17 -0700813 if (refcounted)
814 sock_put(sk);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800815 goto discard_it;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800816}
817
Gerrit Renker73c9e022006-11-10 13:01:31 -0200818static int dccp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
819 int addr_len)
820{
821 struct sockaddr_in6 *usin = (struct sockaddr_in6 *)uaddr;
822 struct inet_connection_sock *icsk = inet_csk(sk);
823 struct inet_sock *inet = inet_sk(sk);
824 struct ipv6_pinfo *np = inet6_sk(sk);
825 struct dccp_sock *dp = dccp_sk(sk);
Arnaud Ebalard20c59de2010-06-01 21:35:01 +0000826 struct in6_addr *saddr = NULL, *final_p, final;
Eric Dumazet45f6fad2015-11-29 19:37:57 -0800827 struct ipv6_txoptions *opt;
David S. Miller4c9483b2011-03-12 16:22:43 -0500828 struct flowi6 fl6;
Gerrit Renker73c9e022006-11-10 13:01:31 -0200829 struct dst_entry *dst;
830 int addr_type;
831 int err;
832
833 dp->dccps_role = DCCP_ROLE_CLIENT;
834
835 if (addr_len < SIN6_LEN_RFC2133)
836 return -EINVAL;
837
838 if (usin->sin6_family != AF_INET6)
839 return -EAFNOSUPPORT;
840
David S. Miller4c9483b2011-03-12 16:22:43 -0500841 memset(&fl6, 0, sizeof(fl6));
Gerrit Renker73c9e022006-11-10 13:01:31 -0200842
843 if (np->sndflow) {
David S. Miller4c9483b2011-03-12 16:22:43 -0500844 fl6.flowlabel = usin->sin6_flowinfo & IPV6_FLOWINFO_MASK;
845 IP6_ECN_flow_init(fl6.flowlabel);
846 if (fl6.flowlabel & IPV6_FLOWLABEL_MASK) {
Gerrit Renker73c9e022006-11-10 13:01:31 -0200847 struct ip6_flowlabel *flowlabel;
David S. Miller4c9483b2011-03-12 16:22:43 -0500848 flowlabel = fl6_sock_lookup(sk, fl6.flowlabel);
Willem de Bruijn59c820b2019-07-07 05:34:45 -0400849 if (IS_ERR(flowlabel))
Gerrit Renker73c9e022006-11-10 13:01:31 -0200850 return -EINVAL;
Gerrit Renker73c9e022006-11-10 13:01:31 -0200851 fl6_sock_release(flowlabel);
852 }
853 }
854 /*
855 * connect() to INADDR_ANY means loopback (BSD'ism).
856 */
857 if (ipv6_addr_any(&usin->sin6_addr))
858 usin->sin6_addr.s6_addr[15] = 1;
859
860 addr_type = ipv6_addr_type(&usin->sin6_addr);
861
862 if (addr_type & IPV6_ADDR_MULTICAST)
863 return -ENETUNREACH;
864
865 if (addr_type & IPV6_ADDR_LINKLOCAL) {
866 if (addr_len >= sizeof(struct sockaddr_in6) &&
867 usin->sin6_scope_id) {
868 /* If interface is set while binding, indices
869 * must coincide.
870 */
871 if (sk->sk_bound_dev_if &&
872 sk->sk_bound_dev_if != usin->sin6_scope_id)
873 return -EINVAL;
874
875 sk->sk_bound_dev_if = usin->sin6_scope_id;
876 }
877
878 /* Connect to link-local address requires an interface */
879 if (!sk->sk_bound_dev_if)
880 return -EINVAL;
881 }
882
Eric Dumazetefe42082013-10-03 15:42:29 -0700883 sk->sk_v6_daddr = usin->sin6_addr;
David S. Miller4c9483b2011-03-12 16:22:43 -0500884 np->flow_label = fl6.flowlabel;
Gerrit Renker73c9e022006-11-10 13:01:31 -0200885
886 /*
887 * DCCP over IPv4
888 */
889 if (addr_type == IPV6_ADDR_MAPPED) {
890 u32 exthdrlen = icsk->icsk_ext_hdr_len;
891 struct sockaddr_in sin;
892
893 SOCK_DEBUG(sk, "connect: ipv4 mapped\n");
894
895 if (__ipv6_only_sock(sk))
896 return -ENETUNREACH;
897
898 sin.sin_family = AF_INET;
899 sin.sin_port = usin->sin6_port;
900 sin.sin_addr.s_addr = usin->sin6_addr.s6_addr32[3];
901
902 icsk->icsk_af_ops = &dccp_ipv6_mapped;
903 sk->sk_backlog_rcv = dccp_v4_do_rcv;
904
905 err = dccp_v4_connect(sk, (struct sockaddr *)&sin, sizeof(sin));
906 if (err) {
907 icsk->icsk_ext_hdr_len = exthdrlen;
908 icsk->icsk_af_ops = &dccp_ipv6_af_ops;
909 sk->sk_backlog_rcv = dccp_v6_do_rcv;
910 goto failure;
Gerrit Renker73c9e022006-11-10 13:01:31 -0200911 }
Eric Dumazetd1e559d2015-03-18 14:05:35 -0700912 np->saddr = sk->sk_v6_rcv_saddr;
Gerrit Renker73c9e022006-11-10 13:01:31 -0200913 return err;
914 }
915
Eric Dumazetefe42082013-10-03 15:42:29 -0700916 if (!ipv6_addr_any(&sk->sk_v6_rcv_saddr))
917 saddr = &sk->sk_v6_rcv_saddr;
Gerrit Renker73c9e022006-11-10 13:01:31 -0200918
David S. Miller4c9483b2011-03-12 16:22:43 -0500919 fl6.flowi6_proto = IPPROTO_DCCP;
Eric Dumazetefe42082013-10-03 15:42:29 -0700920 fl6.daddr = sk->sk_v6_daddr;
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +0000921 fl6.saddr = saddr ? *saddr : np->saddr;
David S. Miller4c9483b2011-03-12 16:22:43 -0500922 fl6.flowi6_oif = sk->sk_bound_dev_if;
David S. Miller1958b852011-03-12 16:36:19 -0500923 fl6.fl6_dport = usin->sin6_port;
924 fl6.fl6_sport = inet->inet_sport;
Paul Moore3df98d72020-09-27 22:38:26 -0400925 security_sk_classify_flow(sk, flowi6_to_flowi_common(&fl6));
Gerrit Renker73c9e022006-11-10 13:01:31 -0200926
Hannes Frederic Sowa1e1d04e2016-04-05 17:10:15 +0200927 opt = rcu_dereference_protected(np->opt, lockdep_sock_is_held(sk));
Eric Dumazet45f6fad2015-11-29 19:37:57 -0800928 final_p = fl6_update_dst(&fl6, opt, &final);
Gerrit Renker73c9e022006-11-10 13:01:31 -0200929
Sabrina Dubrocac4e85f72019-12-04 15:35:52 +0100930 dst = ip6_dst_lookup_flow(sock_net(sk), sk, &fl6, final_p);
David S. Miller68d0c6d2011-03-01 13:19:07 -0800931 if (IS_ERR(dst)) {
932 err = PTR_ERR(dst);
Gerrit Renker73c9e022006-11-10 13:01:31 -0200933 goto failure;
David S. Miller14e50e52007-05-24 18:17:54 -0700934 }
Gerrit Renker73c9e022006-11-10 13:01:31 -0200935
936 if (saddr == NULL) {
David S. Miller4c9483b2011-03-12 16:22:43 -0500937 saddr = &fl6.saddr;
Eric Dumazetefe42082013-10-03 15:42:29 -0700938 sk->sk_v6_rcv_saddr = *saddr;
Gerrit Renker73c9e022006-11-10 13:01:31 -0200939 }
940
941 /* set the source address */
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +0000942 np->saddr = *saddr;
Eric Dumazetc720c7e82009-10-15 06:30:45 +0000943 inet->inet_rcv_saddr = LOOPBACK4_IPV6;
Gerrit Renker73c9e022006-11-10 13:01:31 -0200944
Eric Dumazet6bd4f352015-12-02 21:53:57 -0800945 ip6_dst_store(sk, dst, NULL, NULL);
Gerrit Renker73c9e022006-11-10 13:01:31 -0200946
947 icsk->icsk_ext_hdr_len = 0;
Eric Dumazet45f6fad2015-11-29 19:37:57 -0800948 if (opt)
949 icsk->icsk_ext_hdr_len = opt->opt_flen + opt->opt_nflen;
Gerrit Renker73c9e022006-11-10 13:01:31 -0200950
Eric Dumazetc720c7e82009-10-15 06:30:45 +0000951 inet->inet_dport = usin->sin6_port;
Gerrit Renker73c9e022006-11-10 13:01:31 -0200952
953 dccp_set_state(sk, DCCP_REQUESTING);
954 err = inet6_hash_connect(&dccp_death_row, sk);
955 if (err)
956 goto late_failure;
Gerrit Renkerd7f73652006-11-13 13:34:38 -0200957
958 dp->dccps_iss = secure_dccpv6_sequence_number(np->saddr.s6_addr32,
Eric Dumazetefe42082013-10-03 15:42:29 -0700959 sk->sk_v6_daddr.s6_addr32,
Eric Dumazetc720c7e82009-10-15 06:30:45 +0000960 inet->inet_sport,
961 inet->inet_dport);
Gerrit Renker73c9e022006-11-10 13:01:31 -0200962 err = dccp_connect(sk);
963 if (err)
964 goto late_failure;
965
966 return 0;
967
968late_failure:
969 dccp_set_state(sk, DCCP_CLOSED);
970 __sk_dst_reset(sk);
971failure:
Eric Dumazetc720c7e82009-10-15 06:30:45 +0000972 inet->inet_dport = 0;
Gerrit Renker73c9e022006-11-10 13:01:31 -0200973 sk->sk_route_caps = 0;
974 return err;
975}
976
Stephen Hemminger3b401a82009-09-01 19:25:04 +0000977static const struct inet_connection_sock_af_ops dccp_ipv6_af_ops = {
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -0800978 .queue_xmit = inet6_csk_xmit,
979 .send_check = dccp_v6_send_check,
980 .rebuild_header = inet6_sk_rebuild_header,
981 .conn_request = dccp_v6_conn_request,
982 .syn_recv_sock = dccp_v6_request_recv_sock,
983 .net_header_len = sizeof(struct ipv6hdr),
984 .setsockopt = ipv6_setsockopt,
985 .getsockopt = ipv6_getsockopt,
986 .addr2sockaddr = inet6_csk_addr2sockaddr,
987 .sockaddr_len = sizeof(struct sockaddr_in6),
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800988};
989
990/*
991 * DCCP over IPv4 via INET6 API
992 */
Stephen Hemminger3b401a82009-09-01 19:25:04 +0000993static const struct inet_connection_sock_af_ops dccp_ipv6_mapped = {
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -0800994 .queue_xmit = ip_queue_xmit,
995 .send_check = dccp_v4_send_check,
996 .rebuild_header = inet_sk_rebuild_header,
997 .conn_request = dccp_v6_conn_request,
998 .syn_recv_sock = dccp_v6_request_recv_sock,
999 .net_header_len = sizeof(struct iphdr),
1000 .setsockopt = ipv6_setsockopt,
1001 .getsockopt = ipv6_getsockopt,
1002 .addr2sockaddr = inet6_csk_addr2sockaddr,
1003 .sockaddr_len = sizeof(struct sockaddr_in6),
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001004};
1005
1006/* NOTE: A lot of things set to zero explicitly by call to
1007 * sk_alloc() so need not be done here.
1008 */
1009static int dccp_v6_init_sock(struct sock *sk)
1010{
Arnaldo Carvalho de Melo72478872006-03-20 22:00:37 -08001011 static __u8 dccp_v6_ctl_sock_initialized;
1012 int err = dccp_init_sock(sk, dccp_v6_ctl_sock_initialized);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001013
Arnaldo Carvalho de Melo72478872006-03-20 22:00:37 -08001014 if (err == 0) {
1015 if (unlikely(!dccp_v6_ctl_sock_initialized))
1016 dccp_v6_ctl_sock_initialized = 1;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001017 inet_csk(sk)->icsk_af_ops = &dccp_ipv6_af_ops;
Arnaldo Carvalho de Melo72478872006-03-20 22:00:37 -08001018 }
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001019
1020 return err;
1021}
1022
Brian Haley7d06b2e2008-06-14 17:04:49 -07001023static void dccp_v6_destroy_sock(struct sock *sk)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001024{
Arnaldo Carvalho de Melo3e0fadc2006-03-20 21:23:15 -08001025 dccp_destroy_sock(sk);
Brian Haley7d06b2e2008-06-14 17:04:49 -07001026 inet6_destroy_sock(sk);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001027}
1028
Gerrit Renker73c9e022006-11-10 13:01:31 -02001029static struct timewait_sock_ops dccp6_timewait_sock_ops = {
1030 .twsk_obj_size = sizeof(struct dccp6_timewait_sock),
1031};
1032
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001033static struct proto dccp_v6_prot = {
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001034 .name = "DCCPv6",
1035 .owner = THIS_MODULE,
1036 .close = dccp_close,
1037 .connect = dccp_v6_connect,
1038 .disconnect = dccp_disconnect,
1039 .ioctl = dccp_ioctl,
1040 .init = dccp_v6_init_sock,
1041 .setsockopt = dccp_setsockopt,
1042 .getsockopt = dccp_getsockopt,
1043 .sendmsg = dccp_sendmsg,
1044 .recvmsg = dccp_recvmsg,
1045 .backlog_rcv = dccp_v6_do_rcv,
Craig Gallek496611d2016-02-10 11:50:36 -05001046 .hash = inet6_hash,
Arnaldo Carvalho de Meloab1e0a12008-02-03 04:06:04 -08001047 .unhash = inet_unhash,
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001048 .accept = inet_csk_accept,
Arnaldo Carvalho de Meloab1e0a12008-02-03 04:06:04 -08001049 .get_port = inet_csk_get_port,
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001050 .shutdown = dccp_shutdown,
1051 .destroy = dccp_v6_destroy_sock,
1052 .orphan_count = &dccp_orphan_count,
1053 .max_header = MAX_DCCP_HEADER,
1054 .obj_size = sizeof(struct dccp6_sock),
Paul E. McKenney5f0d5a32017-01-18 02:53:44 -08001055 .slab_flags = SLAB_TYPESAFE_BY_RCU,
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001056 .rsk_prot = &dccp6_request_sock_ops,
1057 .twsk_prot = &dccp6_timewait_sock_ops,
Pavel Emelyanov39d8cda2008-03-22 16:50:58 -07001058 .h.hashinfo = &dccp_hashinfo,
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001059};
1060
Alexey Dobriyan41135cc2009-09-14 12:22:28 +00001061static const struct inet6_protocol dccp_v6_protocol = {
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -08001062 .handler = dccp_v6_rcv,
1063 .err_handler = dccp_v6_err,
1064 .flags = INET6_PROTO_NOPOLICY | INET6_PROTO_FINAL,
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001065};
1066
Alexey Dobriyan5708e862009-09-14 12:23:23 +00001067static const struct proto_ops inet6_dccp_ops = {
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001068 .family = PF_INET6,
1069 .owner = THIS_MODULE,
1070 .release = inet6_release,
1071 .bind = inet6_bind,
1072 .connect = inet_stream_connect,
1073 .socketpair = sock_no_socketpair,
1074 .accept = inet_accept,
1075 .getname = inet6_getname,
Linus Torvaldsa11e1d42018-06-28 09:43:44 -07001076 .poll = dccp_poll,
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001077 .ioctl = inet6_ioctl,
Arnd Bergmannc7cbdbf2019-04-17 22:51:48 +02001078 .gettstamp = sock_gettstamp,
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001079 .listen = inet_dccp_listen,
1080 .shutdown = inet_shutdown,
1081 .setsockopt = sock_common_setsockopt,
1082 .getsockopt = sock_common_getsockopt,
1083 .sendmsg = inet_sendmsg,
1084 .recvmsg = sock_common_recvmsg,
1085 .mmap = sock_no_mmap,
1086 .sendpage = sock_no_sendpage,
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001087#ifdef CONFIG_COMPAT
Christoph Hellwig39869122020-05-18 08:28:06 +02001088 .compat_ioctl = inet6_compat_ioctl,
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001089#endif
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001090};
1091
1092static struct inet_protosw dccp_v6_protosw = {
1093 .type = SOCK_DCCP,
1094 .protocol = IPPROTO_DCCP,
1095 .prot = &dccp_v6_prot,
1096 .ops = &inet6_dccp_ops,
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -08001097 .flags = INET_PROTOSW_ICSK,
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001098};
1099
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00001100static int __net_init dccp_v6_init_net(struct net *net)
Pavel Emelyanov8231bd22008-04-13 22:32:02 -07001101{
Florian Westphalb98b3302021-04-08 19:45:02 +02001102 struct dccp_v6_pernet *pn = net_generic(net, dccp_v6_pernet_id);
1103
Gerrit Renkerd14a0eb2010-03-14 20:13:19 +00001104 if (dccp_hashinfo.bhash == NULL)
1105 return -ESOCKTNOSUPPORT;
Pavel Emelyanov334527d2008-04-13 22:32:45 -07001106
Florian Westphalb98b3302021-04-08 19:45:02 +02001107 return inet_ctl_sock_create(&pn->v6_ctl_sk, PF_INET6,
Gerrit Renkerd14a0eb2010-03-14 20:13:19 +00001108 SOCK_DCCP, IPPROTO_DCCP, net);
Pavel Emelyanov8231bd22008-04-13 22:32:02 -07001109}
1110
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00001111static void __net_exit dccp_v6_exit_net(struct net *net)
Pavel Emelyanov8231bd22008-04-13 22:32:02 -07001112{
Florian Westphalb98b3302021-04-08 19:45:02 +02001113 struct dccp_v6_pernet *pn = net_generic(net, dccp_v6_pernet_id);
1114
1115 inet_ctl_sock_destroy(pn->v6_ctl_sk);
Pavel Emelyanov8231bd22008-04-13 22:32:02 -07001116}
1117
Andrey Ryabininec7cb622017-02-22 12:35:27 +03001118static void __net_exit dccp_v6_exit_batch(struct list_head *net_exit_list)
1119{
1120 inet_twsk_purge(&dccp_hashinfo, AF_INET6);
1121}
1122
Pavel Emelyanov8231bd22008-04-13 22:32:02 -07001123static struct pernet_operations dccp_v6_ops = {
1124 .init = dccp_v6_init_net,
1125 .exit = dccp_v6_exit_net,
Andrey Ryabininec7cb622017-02-22 12:35:27 +03001126 .exit_batch = dccp_v6_exit_batch,
Florian Westphalb98b3302021-04-08 19:45:02 +02001127 .id = &dccp_v6_pernet_id,
1128 .size = sizeof(struct dccp_v6_pernet),
Pavel Emelyanov8231bd22008-04-13 22:32:02 -07001129};
1130
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001131static int __init dccp_v6_init(void)
1132{
1133 int err = proto_register(&dccp_v6_prot, 1);
1134
Xin Longa0f9a4c2017-06-20 15:44:44 +08001135 if (err)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001136 goto out;
1137
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001138 inet6_register_protosw(&dccp_v6_protosw);
Arnaldo Carvalho de Melo72478872006-03-20 22:00:37 -08001139
Pavel Emelyanov8231bd22008-04-13 22:32:02 -07001140 err = register_pernet_subsys(&dccp_v6_ops);
Xin Longa0f9a4c2017-06-20 15:44:44 +08001141 if (err)
Pavel Emelyanov8231bd22008-04-13 22:32:02 -07001142 goto out_destroy_ctl_sock;
Xin Longa0f9a4c2017-06-20 15:44:44 +08001143
1144 err = inet6_add_protocol(&dccp_v6_protocol, IPPROTO_DCCP);
1145 if (err)
1146 goto out_unregister_proto;
1147
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001148out:
1149 return err;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001150out_unregister_proto:
Xin Longa0f9a4c2017-06-20 15:44:44 +08001151 unregister_pernet_subsys(&dccp_v6_ops);
1152out_destroy_ctl_sock:
1153 inet6_unregister_protosw(&dccp_v6_protosw);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001154 proto_unregister(&dccp_v6_prot);
1155 goto out;
1156}
1157
1158static void __exit dccp_v6_exit(void)
1159{
1160 inet6_del_protocol(&dccp_v6_protocol, IPPROTO_DCCP);
Xin Longa0f9a4c2017-06-20 15:44:44 +08001161 unregister_pernet_subsys(&dccp_v6_ops);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001162 inet6_unregister_protosw(&dccp_v6_protosw);
1163 proto_unregister(&dccp_v6_prot);
1164}
1165
1166module_init(dccp_v6_init);
1167module_exit(dccp_v6_exit);
1168
1169/*
1170 * __stringify doesn't likes enums, so use SOCK_DCCP (6) and IPPROTO_DCCP (33)
1171 * values directly, Also cover the case where the protocol is not specified,
1172 * i.e. net-pf-PF_INET6-proto-0-type-SOCK_DCCP
1173 */
Jean Delvare7131c6c2007-10-21 16:45:03 -07001174MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_INET6, 33, 6);
1175MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_INET6, 0, 6);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001176MODULE_LICENSE("GPL");
1177MODULE_AUTHOR("Arnaldo Carvalho de Melo <acme@mandriva.com>");
1178MODULE_DESCRIPTION("DCCPv6 - Datagram Congestion Controlled Protocol");