blob: 6344f1b18a6a1b30cd2f3c559987a2c9e9546f81 [file] [log] [blame]
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001/*
2 * DCCP over IPv6
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -08003 * Linux INET6 implementation
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08004 *
5 * Based on net/dccp6/ipv6.c
6 *
7 * Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * as published by the Free Software Foundation; either version
12 * 2 of the License, or (at your option) any later version.
13 */
14
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -080015#include <linux/module.h>
16#include <linux/random.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090017#include <linux/slab.h>
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -080018#include <linux/xfrm.h>
Andrii323fbd02017-08-31 08:28:01 +030019#include <linux/string.h>
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -080020
21#include <net/addrconf.h>
22#include <net/inet_common.h>
23#include <net/inet_hashtables.h>
Arnaldo Carvalho de Melo14c85022005-12-27 02:43:12 -020024#include <net/inet_sock.h>
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -080025#include <net/inet6_connection_sock.h>
26#include <net/inet6_hashtables.h>
27#include <net/ip6_route.h>
28#include <net/ipv6.h>
29#include <net/protocol.h>
30#include <net/transp_v6.h>
David S. Milleraa0e4e42006-01-06 22:55:39 -080031#include <net/ip6_checksum.h>
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -080032#include <net/xfrm.h>
David S. Miller6e5714e2011-08-03 20:50:44 -070033#include <net/secure_seq.h>
Andrii323fbd02017-08-31 08:28:01 +030034#include <net/sock.h>
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -080035
36#include "dccp.h"
37#include "ipv6.h"
Ian McDonald4b79f0a2006-07-23 23:33:28 -070038#include "feat.h"
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -080039
Pavel Emelyanov13f51d82008-04-14 02:38:45 -070040/* The per-net dccp.v6_ctl_sk is used for sending RSTs and ACKs */
Arnaldo Carvalho de Melo72478872006-03-20 22:00:37 -080041
Stephen Hemminger3b401a82009-09-01 19:25:04 +000042static const struct inet_connection_sock_af_ops dccp_ipv6_mapped;
43static const struct inet_connection_sock_af_ops dccp_ipv6_af_ops;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -080044
Gerrit Renker6f4e5ff2006-11-10 17:43:06 -020045/* add pseudo-header to DCCP checksum stored in skb->csum */
Al Viro868c86b2006-11-14 21:35:48 -080046static inline __sum16 dccp_v6_csum_finish(struct sk_buff *skb,
Eric Dumazetb71d1d42011-04-22 04:53:02 +000047 const struct in6_addr *saddr,
48 const struct in6_addr *daddr)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -080049{
Gerrit Renker6f4e5ff2006-11-10 17:43:06 -020050 return csum_ipv6_magic(saddr, daddr, skb->len, IPPROTO_DCCP, skb->csum);
51}
52
Herbert Xubb296242010-04-11 02:15:55 +000053static inline void dccp_v6_send_check(struct sock *sk, struct sk_buff *skb)
Gerrit Renker6f4e5ff2006-11-10 17:43:06 -020054{
55 struct ipv6_pinfo *np = inet6_sk(sk);
56 struct dccp_hdr *dh = dccp_hdr(skb);
57
58 dccp_csum_outgoing(skb);
Eric Dumazetefe42082013-10-03 15:42:29 -070059 dh->dccph_checksum = dccp_v6_csum_finish(skb, &np->saddr, &sk->sk_v6_daddr);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -080060}
61
David S. Miller6e5714e2011-08-03 20:50:44 -070062static inline __u64 dccp_v6_init_sequence(struct sk_buff *skb)
Gerrit Renkerd7f73652006-11-13 13:34:38 -020063{
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -070064 return secure_dccpv6_sequence_number(ipv6_hdr(skb)->daddr.s6_addr32,
65 ipv6_hdr(skb)->saddr.s6_addr32,
Gerrit Renkerd7f73652006-11-13 13:34:38 -020066 dccp_hdr(skb)->dccph_dport,
67 dccp_hdr(skb)->dccph_sport );
68
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -080069}
70
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -080071static void dccp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
Brian Haleyd5fdd6b2009-06-23 04:31:07 -070072 u8 type, u8 code, int offset, __be32 info)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -080073{
Eric Dumazetb71d1d42011-04-22 04:53:02 +000074 const struct ipv6hdr *hdr = (const struct ipv6hdr *)skb->data;
Eric Dumazet1aa9d1a2016-11-02 20:30:48 -070075 const struct dccp_hdr *dh;
Wei Yongjune0bcfb02008-07-26 11:59:10 +010076 struct dccp_sock *dp;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -080077 struct ipv6_pinfo *np;
78 struct sock *sk;
79 int err;
80 __u64 seq;
Pavel Emelyanovca12a1a2008-07-16 20:28:42 -070081 struct net *net = dev_net(skb->dev);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -080082
Eric Dumazet1aa9d1a2016-11-02 20:30:48 -070083 /* Only need dccph_dport & dccph_sport which are the first
84 * 4 bytes in dccp header.
85 * Our caller (icmpv6_notify()) already pulled 8 bytes for us.
86 */
87 BUILD_BUG_ON(offsetofend(struct dccp_hdr, dccph_sport) > 8);
88 BUILD_BUG_ON(offsetofend(struct dccp_hdr, dccph_dport) > 8);
89 dh = (struct dccp_hdr *)(skb->data + offset);
Wei Yongjun860239c2008-07-26 11:59:11 +010090
Eric Dumazet52036a42015-03-22 10:22:25 -070091 sk = __inet6_lookup_established(net, &dccp_hashinfo,
92 &hdr->daddr, dh->dccph_dport,
93 &hdr->saddr, ntohs(dh->dccph_sport),
David Ahern4297a0e2017-08-07 08:44:21 -070094 inet6_iif(skb), 0);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -080095
Eric Dumazet52036a42015-03-22 10:22:25 -070096 if (!sk) {
Eric Dumazeta16292a2016-04-27 16:44:36 -070097 __ICMP6_INC_STATS(net, __in6_dev_get(skb->dev),
98 ICMP6_MIB_INERRORS);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -080099 return;
100 }
101
102 if (sk->sk_state == DCCP_TIME_WAIT) {
YOSHIFUJI Hideaki9469c7b2006-10-10 19:41:46 -0700103 inet_twsk_put(inet_twsk(sk));
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800104 return;
105 }
Eric Dumazet52036a42015-03-22 10:22:25 -0700106 seq = dccp_hdr_seq(dh);
107 if (sk->sk_state == DCCP_NEW_SYN_RECV)
108 return dccp_req_err(sk, seq);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800109
110 bh_lock_sock(sk);
111 if (sock_owned_by_user(sk))
Eric Dumazet02a1d6e2016-04-27 16:44:39 -0700112 __NET_INC_STATS(net, LINUX_MIB_LOCKDROPPEDICMPS);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800113
114 if (sk->sk_state == DCCP_CLOSED)
115 goto out;
116
Wei Yongjune0bcfb02008-07-26 11:59:10 +0100117 dp = dccp_sk(sk);
Wei Yongjune0bcfb02008-07-26 11:59:10 +0100118 if ((1 << sk->sk_state) & ~(DCCPF_REQUESTING | DCCPF_LISTEN) &&
119 !between48(seq, dp->dccps_awl, dp->dccps_awh)) {
Eric Dumazet02a1d6e2016-04-27 16:44:39 -0700120 __NET_INC_STATS(net, LINUX_MIB_OUTOFWINDOWICMPS);
Wei Yongjune0bcfb02008-07-26 11:59:10 +0100121 goto out;
122 }
123
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800124 np = inet6_sk(sk);
125
David S. Millerec18d9a2012-07-12 00:25:15 -0700126 if (type == NDISC_REDIRECT) {
Jon Maxwell45caeaa2017-03-10 16:40:33 +1100127 if (!sock_owned_by_user(sk)) {
128 struct dst_entry *dst = __sk_dst_check(sk, np->dst_cookie);
David S. Millerec18d9a2012-07-12 00:25:15 -0700129
Jon Maxwell45caeaa2017-03-10 16:40:33 +1100130 if (dst)
131 dst->ops->redirect(dst, sk, skb);
132 }
Duan Jiongbd784a12013-09-18 20:03:27 +0800133 goto out;
David S. Millerec18d9a2012-07-12 00:25:15 -0700134 }
135
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800136 if (type == ICMPV6_PKT_TOOBIG) {
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800137 struct dst_entry *dst = NULL;
138
Hannes Frederic Sowa93b36cf2013-12-15 03:41:14 +0100139 if (!ip6_sk_accept_pmtu(sk))
140 goto out;
141
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800142 if (sock_owned_by_user(sk))
143 goto out;
144 if ((1 << sk->sk_state) & (DCCPF_LISTEN | DCCPF_CLOSED))
145 goto out;
146
David S. Miller35ad9b92012-07-16 03:44:56 -0700147 dst = inet6_csk_update_pmtu(sk, ntohl(info));
148 if (!dst)
149 goto out;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800150
David S. Miller35ad9b92012-07-16 03:44:56 -0700151 if (inet_csk(sk)->icsk_pmtu_cookie > dst_mtu(dst))
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800152 dccp_sync_mss(sk, dst_mtu(dst));
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800153 goto out;
154 }
155
156 icmpv6_err_convert(type, code, &err);
157
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800158 /* Might be for an request_sock */
159 switch (sk->sk_state) {
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800160 case DCCP_REQUESTING:
161 case DCCP_RESPOND: /* Cannot happen.
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800162 It can, it SYNs are crossed. --ANK */
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800163 if (!sock_owned_by_user(sk)) {
Eric Dumazetaa62d762016-04-27 16:44:28 -0700164 __DCCP_INC_STATS(DCCP_MIB_ATTEMPTFAILS);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800165 sk->sk_err = err;
166 /*
167 * Wake people up to see the error
168 * (see connect in sock.c)
169 */
170 sk->sk_error_report(sk);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800171 dccp_done(sk);
172 } else
173 sk->sk_err_soft = err;
174 goto out;
175 }
176
177 if (!sock_owned_by_user(sk) && np->recverr) {
178 sk->sk_err = err;
179 sk->sk_error_report(sk);
180 } else
181 sk->sk_err_soft = err;
182
183out:
184 bh_unlock_sock(sk);
185 sock_put(sk);
186}
187
188
Eric Dumazetea3bea32015-09-25 07:39:23 -0700189static int dccp_v6_send_response(const struct sock *sk, struct request_sock *req)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800190{
Eric Dumazet634fb9792013-10-09 15:21:29 -0700191 struct inet_request_sock *ireq = inet_rsk(req);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800192 struct ipv6_pinfo *np = inet6_sk(sk);
193 struct sk_buff *skb;
Arnaud Ebalard20c59de2010-06-01 21:35:01 +0000194 struct in6_addr *final_p, final;
David S. Miller4c9483b2011-03-12 16:22:43 -0500195 struct flowi6 fl6;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800196 int err = -1;
Denis V. Lunevfd80eb92008-02-29 11:43:03 -0800197 struct dst_entry *dst;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800198
David S. Miller4c9483b2011-03-12 16:22:43 -0500199 memset(&fl6, 0, sizeof(fl6));
200 fl6.flowi6_proto = IPPROTO_DCCP;
Eric Dumazet634fb9792013-10-09 15:21:29 -0700201 fl6.daddr = ireq->ir_v6_rmt_addr;
202 fl6.saddr = ireq->ir_v6_loc_addr;
David S. Miller4c9483b2011-03-12 16:22:43 -0500203 fl6.flowlabel = 0;
Eric Dumazet634fb9792013-10-09 15:21:29 -0700204 fl6.flowi6_oif = ireq->ir_iif;
205 fl6.fl6_dport = ireq->ir_rmt_port;
Eric Dumazetb44084c2013-10-10 00:04:37 -0700206 fl6.fl6_sport = htons(ireq->ir_num);
David S. Miller4c9483b2011-03-12 16:22:43 -0500207 security_req_classify_flow(req, flowi6_to_flowi(&fl6));
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800208
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800209
Eric Dumazet45f6fad2015-11-29 19:37:57 -0800210 rcu_read_lock();
211 final_p = fl6_update_dst(&fl6, rcu_dereference(np->opt), &final);
212 rcu_read_unlock();
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800213
Steffen Klassert0e0d44a2013-08-28 08:04:14 +0200214 dst = ip6_dst_lookup_flow(sk, &fl6, final_p);
David S. Miller68d0c6d2011-03-01 13:19:07 -0800215 if (IS_ERR(dst)) {
216 err = PTR_ERR(dst);
217 dst = NULL;
Denis V. Lunevfd80eb92008-02-29 11:43:03 -0800218 goto done;
David S. Miller68d0c6d2011-03-01 13:19:07 -0800219 }
Denis V. Lunevfd80eb92008-02-29 11:43:03 -0800220
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800221 skb = dccp_make_response(sk, dst, req);
222 if (skb != NULL) {
223 struct dccp_hdr *dh = dccp_hdr(skb);
Huw Davies56ac42b2016-06-27 15:05:28 -0400224 struct ipv6_txoptions *opt;
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800225
Gerrit Renker6f4e5ff2006-11-10 17:43:06 -0200226 dh->dccph_checksum = dccp_v6_csum_finish(skb,
Eric Dumazet634fb9792013-10-09 15:21:29 -0700227 &ireq->ir_v6_loc_addr,
228 &ireq->ir_v6_rmt_addr);
229 fl6.daddr = ireq->ir_v6_rmt_addr;
Eric Dumazet45f6fad2015-11-29 19:37:57 -0800230 rcu_read_lock();
Huw Davies56ac42b2016-06-27 15:05:28 -0400231 opt = ireq->ipv6_opt;
232 if (!opt)
233 opt = rcu_dereference(np->opt);
Pablo Neira92e55f42017-01-26 22:56:21 +0100234 err = ip6_xmit(sk, skb, &fl6, sk->sk_mark, opt, np->tclass);
Eric Dumazet45f6fad2015-11-29 19:37:57 -0800235 rcu_read_unlock();
Gerrit Renkerb9df3cb2006-11-14 11:21:36 -0200236 err = net_xmit_eval(err);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800237 }
238
239done:
David S. Miller0cbd7822006-01-31 17:53:37 -0800240 dst_release(dst);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800241 return err;
242}
243
244static void dccp_v6_reqsk_destructor(struct request_sock *req)
245{
Gerrit Renkerd99a7bd2008-11-04 23:56:30 -0800246 dccp_feat_list_purge(&dccp_rsk(req)->dreq_featneg);
Huw Davies56ac42b2016-06-27 15:05:28 -0400247 kfree(inet_rsk(req)->ipv6_opt);
Eric Dumazet634fb9792013-10-09 15:21:29 -0700248 kfree_skb(inet_rsk(req)->pktopts);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800249}
250
Eric Dumazeta00e7442015-09-29 07:42:39 -0700251static void dccp_v6_ctl_send_reset(const struct sock *sk, struct sk_buff *rxskb)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800252{
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000253 const struct ipv6hdr *rxip6h;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800254 struct sk_buff *skb;
David S. Miller4c9483b2011-03-12 16:22:43 -0500255 struct flowi6 fl6;
Eric Dumazetadf30902009-06-02 05:19:30 +0000256 struct net *net = dev_net(skb_dst(rxskb)->dev);
Pavel Emelyanov334527d2008-04-13 22:32:45 -0700257 struct sock *ctl_sk = net->dccp.v6_ctl_sk;
Eric Dumazetadf30902009-06-02 05:19:30 +0000258 struct dst_entry *dst;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800259
Gerrit Renkere356d372007-09-26 14:35:19 -0300260 if (dccp_hdr(rxskb)->dccph_type == DCCP_PKT_RESET)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800261 return;
262
263 if (!ipv6_unicast_destination(rxskb))
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800264 return;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800265
Pavel Emelyanov02047742008-04-13 22:32:25 -0700266 skb = dccp_ctl_make_reset(ctl_sk, rxskb);
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800267 if (skb == NULL)
Arnaldo Carvalho de Melo8109b022006-12-10 16:01:18 -0200268 return;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800269
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700270 rxip6h = ipv6_hdr(rxskb);
Gerrit Renkere356d372007-09-26 14:35:19 -0300271 dccp_hdr(skb)->dccph_checksum = dccp_v6_csum_finish(skb, &rxip6h->saddr,
272 &rxip6h->daddr);
Gerrit Renker6f4e5ff2006-11-10 17:43:06 -0200273
David S. Miller4c9483b2011-03-12 16:22:43 -0500274 memset(&fl6, 0, sizeof(fl6));
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +0000275 fl6.daddr = rxip6h->saddr;
276 fl6.saddr = rxip6h->daddr;
Gerrit Renker6f4e5ff2006-11-10 17:43:06 -0200277
David S. Miller4c9483b2011-03-12 16:22:43 -0500278 fl6.flowi6_proto = IPPROTO_DCCP;
279 fl6.flowi6_oif = inet6_iif(rxskb);
David S. Miller1958b852011-03-12 16:36:19 -0500280 fl6.fl6_dport = dccp_hdr(skb)->dccph_dport;
281 fl6.fl6_sport = dccp_hdr(skb)->dccph_sport;
David S. Miller4c9483b2011-03-12 16:22:43 -0500282 security_skb_classify_flow(rxskb, flowi6_to_flowi(&fl6));
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800283
284 /* sk = NULL, but it is safe for now. RST socket required. */
Steffen Klassert0e0d44a2013-08-28 08:04:14 +0200285 dst = ip6_dst_lookup_flow(ctl_sk, &fl6, NULL);
David S. Miller68d0c6d2011-03-01 13:19:07 -0800286 if (!IS_ERR(dst)) {
287 skb_dst_set(skb, dst);
Pablo Neira92e55f42017-01-26 22:56:21 +0100288 ip6_xmit(ctl_sk, skb, &fl6, 0, NULL, 0);
Eric Dumazet7309f882016-04-29 14:16:49 -0700289 DCCP_INC_STATS(DCCP_MIB_OUTSEGS);
290 DCCP_INC_STATS(DCCP_MIB_OUTRSTS);
David S. Miller68d0c6d2011-03-01 13:19:07 -0800291 return;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800292 }
293
294 kfree_skb(skb);
295}
296
Gerrit Renker73c9e022006-11-10 13:01:31 -0200297static struct request_sock_ops dccp6_request_sock_ops = {
298 .family = AF_INET6,
299 .obj_size = sizeof(struct dccp6_request_sock),
300 .rtx_syn_ack = dccp_v6_send_response,
301 .send_ack = dccp_reqsk_send_ack,
302 .destructor = dccp_v6_reqsk_destructor,
303 .send_reset = dccp_v6_ctl_send_reset,
Eric Dumazetc72e1182012-04-12 22:16:05 +0000304 .syn_ack_timeout = dccp_syn_ack_timeout,
Gerrit Renker73c9e022006-11-10 13:01:31 -0200305};
306
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800307static int dccp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
308{
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800309 struct request_sock *req;
310 struct dccp_request_sock *dreq;
Eric Dumazet634fb9792013-10-09 15:21:29 -0700311 struct inet_request_sock *ireq;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800312 struct ipv6_pinfo *np = inet6_sk(sk);
Arnaldo Carvalho de Melo8109b022006-12-10 16:01:18 -0200313 const __be32 service = dccp_hdr_request(skb)->dccph_req_service;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800314 struct dccp_skb_cb *dcb = DCCP_SKB_CB(skb);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800315
316 if (skb->protocol == htons(ETH_P_IP))
317 return dccp_v4_conn_request(sk, skb);
318
319 if (!ipv6_unicast_destination(skb))
Gerrit Renker4a5409a2007-10-04 14:52:28 -0700320 return 0; /* discard, don't send a reset here */
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800321
322 if (dccp_bad_service_code(sk, service)) {
Gerrit Renker4a5409a2007-10-04 14:52:28 -0700323 dcb->dccpd_reset_code = DCCP_RESET_CODE_BAD_SERVICE_CODE;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800324 goto drop;
Arnaldo Carvalho de Melo8109b022006-12-10 16:01:18 -0200325 }
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800326 /*
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800327 * There are no SYN attacks on IPv6, yet...
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800328 */
Gerrit Renker4a5409a2007-10-04 14:52:28 -0700329 dcb->dccpd_reset_code = DCCP_RESET_CODE_TOO_BUSY;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800330 if (inet_csk_reqsk_queue_is_full(sk))
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800331 goto drop;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800332
Eric Dumazet5ea8ea22016-10-26 09:27:57 -0700333 if (sk_acceptq_is_full(sk))
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800334 goto drop;
335
Eric Dumazeta1a53442015-10-04 21:08:11 -0700336 req = inet_reqsk_alloc(&dccp6_request_sock_ops, sk, true);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800337 if (req == NULL)
338 goto drop;
339
Gerrit Renkerac757732008-11-04 23:55:49 -0800340 if (dccp_reqsk_init(req, dccp_sk(sk), skb))
341 goto drop_and_free;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800342
Gerrit Renker8b819412007-12-13 12:29:24 -0200343 dreq = dccp_rsk(req);
344 if (dccp_parse_options(sk, dreq, skb))
345 goto drop_and_free;
346
Venkat Yekkirala4237c752006-07-24 23:32:50 -0700347 if (security_inet_conn_request(sk, skb, req))
348 goto drop_and_free;
349
Eric Dumazet634fb9792013-10-09 15:21:29 -0700350 ireq = inet_rsk(req);
351 ireq->ir_v6_rmt_addr = ipv6_hdr(skb)->saddr;
352 ireq->ir_v6_loc_addr = ipv6_hdr(skb)->daddr;
Eric Dumazet3f66b082015-03-12 16:44:10 -0700353 ireq->ireq_family = AF_INET6;
Eric Dumazetb855ff82018-04-07 13:42:41 -0700354 ireq->ir_mark = inet_request_mark(sk, skb);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800355
Eric Dumazeta2247722014-09-27 09:50:56 -0700356 if (ipv6_opt_accepted(sk, skb, IP6CB(skb)) ||
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800357 np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo ||
358 np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim) {
Reshetova, Elena63354792017-06-30 13:07:58 +0300359 refcount_inc(&skb->users);
Eric Dumazet634fb9792013-10-09 15:21:29 -0700360 ireq->pktopts = skb;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800361 }
Eric Dumazet634fb9792013-10-09 15:21:29 -0700362 ireq->ir_iif = sk->sk_bound_dev_if;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800363
364 /* So that link locals have meaning */
365 if (!sk->sk_bound_dev_if &&
Eric Dumazet634fb9792013-10-09 15:21:29 -0700366 ipv6_addr_type(&ireq->ir_v6_rmt_addr) & IPV6_ADDR_LINKLOCAL)
367 ireq->ir_iif = inet6_iif(skb);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800368
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800369 /*
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800370 * Step 3: Process LISTEN state
371 *
Gerrit Renkerd83ca5a2006-11-10 16:29:14 -0200372 * Set S.ISR, S.GSR, S.SWL, S.SWH from packet or Init Cookie
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800373 *
Samuel Jerof541fb72012-02-26 18:22:02 -0700374 * Setting S.SWL/S.SWH to is deferred to dccp_create_openreq_child().
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800375 */
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800376 dreq->dreq_isr = dcb->dccpd_seq;
Samuel Jerof541fb72012-02-26 18:22:02 -0700377 dreq->dreq_gsr = dreq->dreq_isr;
Gerrit Renker865e9022006-11-13 13:31:50 -0200378 dreq->dreq_iss = dccp_v6_init_sequence(skb);
Samuel Jerof541fb72012-02-26 18:22:02 -0700379 dreq->dreq_gss = dreq->dreq_iss;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800380 dreq->dreq_service = service;
381
Christoph Paasch1a2c6182013-03-17 08:23:34 +0000382 if (dccp_v6_send_response(sk, req))
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800383 goto drop_and_free;
384
Eric Dumazet079096f2015-10-02 11:43:32 -0700385 inet_csk_reqsk_queue_hash_add(sk, req, DCCP_TIMEOUT_INIT);
Xin Long0c2232b2017-07-26 14:19:09 +0800386 reqsk_put(req);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800387 return 0;
388
389drop_and_free:
390 reqsk_free(req);
391drop:
Eric Dumazetaa62d762016-04-27 16:44:28 -0700392 __DCCP_INC_STATS(DCCP_MIB_ATTEMPTFAILS);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800393 return -1;
394}
395
Eric Dumazet0c271712015-09-29 07:42:48 -0700396static struct sock *dccp_v6_request_recv_sock(const struct sock *sk,
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800397 struct sk_buff *skb,
398 struct request_sock *req,
Eric Dumazet5e0724d2015-10-22 08:20:46 -0700399 struct dst_entry *dst,
400 struct request_sock *req_unhash,
401 bool *own_req)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800402{
Eric Dumazet634fb9792013-10-09 15:21:29 -0700403 struct inet_request_sock *ireq = inet_rsk(req);
Eric Dumazet0c271712015-09-29 07:42:48 -0700404 struct ipv6_pinfo *newnp;
405 const struct ipv6_pinfo *np = inet6_sk(sk);
Eric Dumazet45f6fad2015-11-29 19:37:57 -0800406 struct ipv6_txoptions *opt;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800407 struct inet_sock *newinet;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800408 struct dccp6_sock *newdp6;
409 struct sock *newsk;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800410
411 if (skb->protocol == htons(ETH_P_IP)) {
412 /*
413 * v6 mapped
414 */
Eric Dumazet5e0724d2015-10-22 08:20:46 -0700415 newsk = dccp_v4_request_recv_sock(sk, skb, req, dst,
416 req_unhash, own_req);
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800417 if (newsk == NULL)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800418 return NULL;
419
420 newdp6 = (struct dccp6_sock *)newsk;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800421 newinet = inet_sk(newsk);
422 newinet->pinet6 = &newdp6->inet6;
423 newnp = inet6_sk(newsk);
424
425 memcpy(newnp, np, sizeof(struct ipv6_pinfo));
426
Eric Dumazetd1e559d2015-03-18 14:05:35 -0700427 newnp->saddr = newsk->sk_v6_rcv_saddr;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800428
429 inet_csk(newsk)->icsk_af_ops = &dccp_ipv6_mapped;
430 newsk->sk_backlog_rcv = dccp_v4_do_rcv;
431 newnp->pktoptions = NULL;
432 newnp->opt = NULL;
WANG Cong83eadda2017-05-09 16:59:54 -0700433 newnp->ipv6_mc_list = NULL;
434 newnp->ipv6_ac_list = NULL;
435 newnp->ipv6_fl_list = NULL;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800436 newnp->mcast_oif = inet6_iif(skb);
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700437 newnp->mcast_hops = ipv6_hdr(skb)->hop_limit;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800438
439 /*
440 * No need to charge this sock to the relevant IPv6 refcnt debug socks count
441 * here, dccp_create_openreq_child now does this for us, see the comment in
442 * that function for the gory details. -acme
443 */
444
445 /* It is tricky place. Until this moment IPv4 tcp
446 worked with IPv6 icsk.icsk_af_ops.
447 Sync it now.
448 */
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -0800449 dccp_sync_mss(newsk, inet_csk(newsk)->icsk_pmtu_cookie);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800450
451 return newsk;
452 }
453
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800454
455 if (sk_acceptq_is_full(sk))
456 goto out_overflow;
457
Eric Dumazetf76b33c2015-09-29 07:42:42 -0700458 if (!dst) {
David S. Miller4c9483b2011-03-12 16:22:43 -0500459 struct flowi6 fl6;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800460
Eric Dumazetf76b33c2015-09-29 07:42:42 -0700461 dst = inet6_csk_route_req(sk, &fl6, req, IPPROTO_DCCP);
462 if (!dst)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800463 goto out;
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800464 }
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800465
466 newsk = dccp_create_openreq_child(sk, req, skb);
467 if (newsk == NULL)
Balazs Scheidler093d2822010-10-21 13:06:43 +0200468 goto out_nonewsk;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800469
470 /*
471 * No need to charge this sock to the relevant IPv6 refcnt debug socks
472 * count here, dccp_create_openreq_child now does this for us, see the
473 * comment in that function for the gory details. -acme
474 */
475
Eric Dumazet6bd4f352015-12-02 21:53:57 -0800476 ip6_dst_store(newsk, dst, NULL, NULL);
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800477 newsk->sk_route_caps = dst->dev->features & ~(NETIF_F_IP_CSUM |
478 NETIF_F_TSO);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800479 newdp6 = (struct dccp6_sock *)newsk;
480 newinet = inet_sk(newsk);
481 newinet->pinet6 = &newdp6->inet6;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800482 newnp = inet6_sk(newsk);
483
484 memcpy(newnp, np, sizeof(struct ipv6_pinfo));
485
Eric Dumazet634fb9792013-10-09 15:21:29 -0700486 newsk->sk_v6_daddr = ireq->ir_v6_rmt_addr;
487 newnp->saddr = ireq->ir_v6_loc_addr;
488 newsk->sk_v6_rcv_saddr = ireq->ir_v6_loc_addr;
489 newsk->sk_bound_dev_if = ireq->ir_iif;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800490
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800491 /* Now IPv6 options...
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800492
493 First: no IPv4 options.
494 */
Eric Dumazetf6d8bd02011-04-21 09:45:37 +0000495 newinet->inet_opt = NULL;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800496
497 /* Clone RX bits */
498 newnp->rxopt.all = np->rxopt.all;
499
WANG Cong83eadda2017-05-09 16:59:54 -0700500 newnp->ipv6_mc_list = NULL;
501 newnp->ipv6_ac_list = NULL;
502 newnp->ipv6_fl_list = NULL;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800503 newnp->pktoptions = NULL;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800504 newnp->opt = NULL;
505 newnp->mcast_oif = inet6_iif(skb);
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700506 newnp->mcast_hops = ipv6_hdr(skb)->hop_limit;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800507
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800508 /*
509 * Clone native IPv6 options from listening socket (if any)
510 *
511 * Yes, keeping reference count would be much more clever, but we make
512 * one more one thing there: reattach optmem to newsk.
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800513 */
Huw Davies56ac42b2016-06-27 15:05:28 -0400514 opt = ireq->ipv6_opt;
515 if (!opt)
516 opt = rcu_dereference(np->opt);
Eric Dumazet45f6fad2015-11-29 19:37:57 -0800517 if (opt) {
518 opt = ipv6_dup_options(newsk, opt);
519 RCU_INIT_POINTER(newnp->opt, opt);
520 }
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -0800521 inet_csk(newsk)->icsk_ext_hdr_len = 0;
Eric Dumazet45f6fad2015-11-29 19:37:57 -0800522 if (opt)
523 inet_csk(newsk)->icsk_ext_hdr_len = opt->opt_nflen +
524 opt->opt_flen;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800525
526 dccp_sync_mss(newsk, dst_mtu(dst));
527
Eric Dumazetc720c7e2009-10-15 06:30:45 +0000528 newinet->inet_daddr = newinet->inet_saddr = LOOPBACK4_IPV6;
529 newinet->inet_rcv_saddr = LOOPBACK4_IPV6;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800530
Balazs Scheidler093d2822010-10-21 13:06:43 +0200531 if (__inet_inherit_port(sk, newsk) < 0) {
Christoph Paasche337e242012-12-14 04:07:58 +0000532 inet_csk_prepare_forced_close(newsk);
533 dccp_done(newsk);
Balazs Scheidler093d2822010-10-21 13:06:43 +0200534 goto out;
535 }
Eric Dumazet5e0724d2015-10-22 08:20:46 -0700536 *own_req = inet_ehash_nolisten(newsk, req_to_sk(req_unhash));
Eric Dumazetce105002015-10-30 09:46:12 -0700537 /* Clone pktoptions received with SYN, if we own the req */
538 if (*own_req && ireq->pktopts) {
539 newnp->pktoptions = skb_clone(ireq->pktopts, GFP_ATOMIC);
540 consume_skb(ireq->pktopts);
541 ireq->pktopts = NULL;
542 if (newnp->pktoptions)
543 skb_set_owner_r(newnp->pktoptions, newsk);
544 }
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800545
546 return newsk;
547
548out_overflow:
Eric Dumazet02a1d6e2016-04-27 16:44:39 -0700549 __NET_INC_STATS(sock_net(sk), LINUX_MIB_LISTENOVERFLOWS);
Balazs Scheidler093d2822010-10-21 13:06:43 +0200550out_nonewsk:
551 dst_release(dst);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800552out:
Eric Dumazet02a1d6e2016-04-27 16:44:39 -0700553 __NET_INC_STATS(sock_net(sk), LINUX_MIB_LISTENDROPS);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800554 return NULL;
555}
556
557/* The socket must have it's spinlock held when we get
558 * here.
559 *
560 * We have a potential double-lock case here, so even when
561 * doing backlog processing we use the BH locking scheme.
562 * This is because we cannot sleep with the original spinlock
563 * held.
564 */
565static int dccp_v6_do_rcv(struct sock *sk, struct sk_buff *skb)
566{
567 struct ipv6_pinfo *np = inet6_sk(sk);
568 struct sk_buff *opt_skb = NULL;
569
570 /* Imagine: socket is IPv6. IPv4 packet arrives,
571 goes to IPv4 receive handler and backlogged.
572 From backlog it always goes here. Kerboom...
573 Fortunately, dccp_rcv_established and rcv_established
574 handle them correctly, but it is not case with
575 dccp_v6_hnd_req and dccp_v6_ctl_send_reset(). --ANK
576 */
577
578 if (skb->protocol == htons(ETH_P_IP))
579 return dccp_v4_do_rcv(sk, skb);
580
Dmitry Mishinfda9ef52006-08-31 15:28:39 -0700581 if (sk_filter(sk, skb))
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800582 goto discard;
583
584 /*
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800585 * socket locking is here for SMP purposes as backlog rcv is currently
586 * called with bh processing disabled.
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800587 */
588
589 /* Do Stevens' IPV6_PKTOPTIONS.
590
591 Yes, guys, it is the only place in our code, where we
592 may make it not affecting IPv4.
593 The rest of code is protocol independent,
594 and I do not like idea to uglify IPv4.
595
596 Actually, all the idea behind IPV6_PKTOPTIONS
597 looks not very well thought. For now we latch
598 options, received in the last packet, enqueued
599 by tcp. Feel free to propose better solution.
YOSHIFUJI Hideakic9eaf172007-02-09 23:24:38 +0900600 --ANK (980728)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800601 */
602 if (np->rxopt.all)
603 opt_skb = skb_clone(skb, GFP_ATOMIC);
604
605 if (sk->sk_state == DCCP_OPEN) { /* Fast path */
606 if (dccp_rcv_established(sk, skb, dccp_hdr(skb), skb->len))
607 goto reset;
Andrii323fbd02017-08-31 08:28:01 +0300608 if (opt_skb)
609 goto ipv6_pktoptions;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800610 return 0;
611 }
612
Gerrit Renkerd83ca5a2006-11-10 16:29:14 -0200613 /*
614 * Step 3: Process LISTEN state
615 * If S.state == LISTEN,
616 * If P.type == Request or P contains a valid Init Cookie option,
617 * (* Must scan the packet's options to check for Init
618 * Cookies. Only Init Cookies are processed here,
619 * however; other options are processed in Step 8. This
620 * scan need only be performed if the endpoint uses Init
621 * Cookies *)
622 * (* Generate a new socket and switch to that socket *)
623 * Set S := new socket for this port pair
624 * S.state = RESPOND
625 * Choose S.ISS (initial seqno) or set from Init Cookies
626 * Initialize S.GAR := S.ISS
627 * Set S.ISR, S.GSR, S.SWL, S.SWH from packet or Init Cookies
628 * Continue with S.state == RESPOND
629 * (* A Response packet will be generated in Step 11 *)
630 * Otherwise,
631 * Generate Reset(No Connection) unless P.type == Reset
632 * Drop packet and return
633 *
634 * NOTE: the check for the packet types is done in
635 * dccp_rcv_state_process
636 */
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800637
638 if (dccp_rcv_state_process(sk, skb, dccp_hdr(skb), skb->len))
639 goto reset;
Andrii323fbd02017-08-31 08:28:01 +0300640 if (opt_skb)
641 goto ipv6_pktoptions;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800642 return 0;
643
644reset:
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800645 dccp_v6_ctl_send_reset(sk, skb);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800646discard:
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800647 if (opt_skb != NULL)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800648 __kfree_skb(opt_skb);
649 kfree_skb(skb);
650 return 0;
Andrii323fbd02017-08-31 08:28:01 +0300651
652/* Handling IPV6_PKTOPTIONS skb the similar
653 * way it's done for net/ipv6/tcp_ipv6.c
654 */
655ipv6_pktoptions:
656 if (!((1 << sk->sk_state) & (DCCPF_CLOSED | DCCPF_LISTEN))) {
657 if (np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo)
658 np->mcast_oif = inet6_iif(opt_skb);
659 if (np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim)
660 np->mcast_hops = ipv6_hdr(opt_skb)->hop_limit;
661 if (np->rxopt.bits.rxflow || np->rxopt.bits.rxtclass)
662 np->rcv_flowinfo = ip6_flowinfo(ipv6_hdr(opt_skb));
663 if (np->repflow)
664 np->flow_label = ip6_flowlabel(ipv6_hdr(opt_skb));
665 if (ipv6_opt_accepted(sk, opt_skb,
666 &DCCP_SKB_CB(opt_skb)->header.h6)) {
667 skb_set_owner_r(opt_skb, sk);
668 memmove(IP6CB(opt_skb),
669 &DCCP_SKB_CB(opt_skb)->header.h6,
670 sizeof(struct inet6_skb_parm));
671 opt_skb = xchg(&np->pktoptions, opt_skb);
672 } else {
673 __kfree_skb(opt_skb);
674 opt_skb = xchg(&np->pktoptions, NULL);
675 }
676 }
677
678 kfree_skb(opt_skb);
679 return 0;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800680}
681
Herbert Xue5bbef22007-10-15 12:50:28 -0700682static int dccp_v6_rcv(struct sk_buff *skb)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800683{
684 const struct dccp_hdr *dh;
Eric Dumazet3b24d852016-04-01 08:52:17 -0700685 bool refcounted;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800686 struct sock *sk;
Gerrit Renker6f4e5ff2006-11-10 17:43:06 -0200687 int min_cov;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800688
Gerrit Renker6f4e5ff2006-11-10 17:43:06 -0200689 /* Step 1: Check header basics */
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800690
691 if (dccp_invalid_packet(skb))
692 goto discard_it;
693
Gerrit Renker6f4e5ff2006-11-10 17:43:06 -0200694 /* Step 1: If header checksum is incorrect, drop packet and return. */
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700695 if (dccp_v6_csum_finish(skb, &ipv6_hdr(skb)->saddr,
696 &ipv6_hdr(skb)->daddr)) {
Gerrit Renker59348b12006-11-20 18:39:23 -0200697 DCCP_WARN("dropped packet with invalid checksum\n");
Gerrit Renker6f4e5ff2006-11-10 17:43:06 -0200698 goto discard_it;
699 }
700
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800701 dh = dccp_hdr(skb);
702
Gerrit Renkerfde20102007-10-24 10:12:09 -0200703 DCCP_SKB_CB(skb)->dccpd_seq = dccp_hdr_seq(dh);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800704 DCCP_SKB_CB(skb)->dccpd_type = dh->dccph_type;
705
706 if (dccp_packet_without_ack(skb))
707 DCCP_SKB_CB(skb)->dccpd_ack_seq = DCCP_PKT_WITHOUT_ACK_SEQ;
708 else
709 DCCP_SKB_CB(skb)->dccpd_ack_seq = dccp_hdr_ack_seq(skb);
710
Eric Dumazet4bdc3d62015-10-13 17:12:54 -0700711lookup:
Craig Galleka5836362016-02-10 11:50:38 -0500712 sk = __inet6_lookup_skb(&dccp_hashinfo, skb, __dccp_hdr_len(dh),
Eric Dumazet870c3152014-10-17 09:17:20 -0700713 dh->dccph_sport, dh->dccph_dport,
David Ahern4297a0e2017-08-07 08:44:21 -0700714 inet6_iif(skb), 0, &refcounted);
Eric Dumazet4bdc3d62015-10-13 17:12:54 -0700715 if (!sk) {
Gerrit Renkerd23c7102006-11-10 11:46:34 -0200716 dccp_pr_debug("failed to look up flow ID in table and "
717 "get corresponding socket\n");
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800718 goto no_dccp_socket;
Gerrit Renkerd23c7102006-11-10 11:46:34 -0200719 }
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800720
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800721 /*
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800722 * Step 2:
Arnaldo Carvalho de Melo8109b022006-12-10 16:01:18 -0200723 * ... or S.state == TIMEWAIT,
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800724 * Generate Reset(No Connection) unless P.type == Reset
725 * Drop packet and return
726 */
Gerrit Renkerd23c7102006-11-10 11:46:34 -0200727 if (sk->sk_state == DCCP_TIME_WAIT) {
728 dccp_pr_debug("sk->sk_state == DCCP_TIME_WAIT: do_time_wait\n");
729 inet_twsk_put(inet_twsk(sk));
730 goto no_dccp_socket;
731 }
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800732
Eric Dumazet079096f2015-10-02 11:43:32 -0700733 if (sk->sk_state == DCCP_NEW_SYN_RECV) {
734 struct request_sock *req = inet_reqsk(sk);
Eric Dumazet77166822016-02-18 05:39:18 -0800735 struct sock *nsk;
Eric Dumazet079096f2015-10-02 11:43:32 -0700736
737 sk = req->rsk_listener;
Eric Dumazet77166822016-02-18 05:39:18 -0800738 if (unlikely(sk->sk_state != DCCP_LISTEN)) {
Eric Dumazetf03f2e12015-10-14 11:16:27 -0700739 inet_csk_reqsk_queue_drop_and_put(sk, req);
Eric Dumazet4bdc3d62015-10-13 17:12:54 -0700740 goto lookup;
741 }
Eric Dumazet77166822016-02-18 05:39:18 -0800742 sock_hold(sk);
Eric Dumazet3b24d852016-04-01 08:52:17 -0700743 refcounted = true;
Eric Dumazet77166822016-02-18 05:39:18 -0800744 nsk = dccp_check_req(sk, skb, req);
Eric Dumazet079096f2015-10-02 11:43:32 -0700745 if (!nsk) {
746 reqsk_put(req);
Eric Dumazet77166822016-02-18 05:39:18 -0800747 goto discard_and_relse;
Eric Dumazet079096f2015-10-02 11:43:32 -0700748 }
749 if (nsk == sk) {
Eric Dumazet079096f2015-10-02 11:43:32 -0700750 reqsk_put(req);
751 } else if (dccp_child_process(sk, nsk, skb)) {
752 dccp_v6_ctl_send_reset(sk, skb);
Eric Dumazet77166822016-02-18 05:39:18 -0800753 goto discard_and_relse;
Eric Dumazet079096f2015-10-02 11:43:32 -0700754 } else {
Eric Dumazet77166822016-02-18 05:39:18 -0800755 sock_put(sk);
Eric Dumazet079096f2015-10-02 11:43:32 -0700756 return 0;
757 }
758 }
Gerrit Renker6f4e5ff2006-11-10 17:43:06 -0200759 /*
760 * RFC 4340, sec. 9.2.1: Minimum Checksum Coverage
Arnaldo Carvalho de Melo8109b022006-12-10 16:01:18 -0200761 * o if MinCsCov = 0, only packets with CsCov = 0 are accepted
762 * o if MinCsCov > 0, also accept packets with CsCov >= MinCsCov
Gerrit Renker6f4e5ff2006-11-10 17:43:06 -0200763 */
764 min_cov = dccp_sk(sk)->dccps_pcrlen;
765 if (dh->dccph_cscov && (min_cov == 0 || dh->dccph_cscov < min_cov)) {
766 dccp_pr_debug("Packet CsCov %d does not satisfy MinCsCov %d\n",
767 dh->dccph_cscov, min_cov);
768 /* FIXME: send Data Dropped option (see also dccp_v4_rcv) */
769 goto discard_and_relse;
770 }
771
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800772 if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb))
773 goto discard_and_relse;
774
Eric Dumazetc3f24cf2016-11-02 17:14:41 -0700775 return __sk_receive_skb(sk, skb, 1, dh->dccph_doff * 4,
776 refcounted) ? -1 : 0;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800777
778no_dccp_socket:
779 if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb))
780 goto discard_it;
781 /*
782 * Step 2:
Arnaldo Carvalho de Melo8109b022006-12-10 16:01:18 -0200783 * If no socket ...
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800784 * Generate Reset(No Connection) unless P.type == Reset
785 * Drop packet and return
786 */
787 if (dh->dccph_type != DCCP_PKT_RESET) {
788 DCCP_SKB_CB(skb)->dccpd_reset_code =
789 DCCP_RESET_CODE_NO_CONNECTION;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800790 dccp_v6_ctl_send_reset(sk, skb);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800791 }
Gerrit Renkerd23c7102006-11-10 11:46:34 -0200792
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800793discard_it:
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800794 kfree_skb(skb);
795 return 0;
796
797discard_and_relse:
Eric Dumazet3b24d852016-04-01 08:52:17 -0700798 if (refcounted)
799 sock_put(sk);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800800 goto discard_it;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800801}
802
Gerrit Renker73c9e022006-11-10 13:01:31 -0200803static int dccp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
804 int addr_len)
805{
806 struct sockaddr_in6 *usin = (struct sockaddr_in6 *)uaddr;
807 struct inet_connection_sock *icsk = inet_csk(sk);
808 struct inet_sock *inet = inet_sk(sk);
809 struct ipv6_pinfo *np = inet6_sk(sk);
810 struct dccp_sock *dp = dccp_sk(sk);
Arnaud Ebalard20c59de2010-06-01 21:35:01 +0000811 struct in6_addr *saddr = NULL, *final_p, final;
Eric Dumazet45f6fad2015-11-29 19:37:57 -0800812 struct ipv6_txoptions *opt;
David S. Miller4c9483b2011-03-12 16:22:43 -0500813 struct flowi6 fl6;
Gerrit Renker73c9e022006-11-10 13:01:31 -0200814 struct dst_entry *dst;
815 int addr_type;
816 int err;
817
818 dp->dccps_role = DCCP_ROLE_CLIENT;
819
820 if (addr_len < SIN6_LEN_RFC2133)
821 return -EINVAL;
822
823 if (usin->sin6_family != AF_INET6)
824 return -EAFNOSUPPORT;
825
David S. Miller4c9483b2011-03-12 16:22:43 -0500826 memset(&fl6, 0, sizeof(fl6));
Gerrit Renker73c9e022006-11-10 13:01:31 -0200827
828 if (np->sndflow) {
David S. Miller4c9483b2011-03-12 16:22:43 -0500829 fl6.flowlabel = usin->sin6_flowinfo & IPV6_FLOWINFO_MASK;
830 IP6_ECN_flow_init(fl6.flowlabel);
831 if (fl6.flowlabel & IPV6_FLOWLABEL_MASK) {
Gerrit Renker73c9e022006-11-10 13:01:31 -0200832 struct ip6_flowlabel *flowlabel;
David S. Miller4c9483b2011-03-12 16:22:43 -0500833 flowlabel = fl6_sock_lookup(sk, fl6.flowlabel);
Gerrit Renker73c9e022006-11-10 13:01:31 -0200834 if (flowlabel == NULL)
835 return -EINVAL;
Gerrit Renker73c9e022006-11-10 13:01:31 -0200836 fl6_sock_release(flowlabel);
837 }
838 }
839 /*
840 * connect() to INADDR_ANY means loopback (BSD'ism).
841 */
842 if (ipv6_addr_any(&usin->sin6_addr))
843 usin->sin6_addr.s6_addr[15] = 1;
844
845 addr_type = ipv6_addr_type(&usin->sin6_addr);
846
847 if (addr_type & IPV6_ADDR_MULTICAST)
848 return -ENETUNREACH;
849
850 if (addr_type & IPV6_ADDR_LINKLOCAL) {
851 if (addr_len >= sizeof(struct sockaddr_in6) &&
852 usin->sin6_scope_id) {
853 /* If interface is set while binding, indices
854 * must coincide.
855 */
856 if (sk->sk_bound_dev_if &&
857 sk->sk_bound_dev_if != usin->sin6_scope_id)
858 return -EINVAL;
859
860 sk->sk_bound_dev_if = usin->sin6_scope_id;
861 }
862
863 /* Connect to link-local address requires an interface */
864 if (!sk->sk_bound_dev_if)
865 return -EINVAL;
866 }
867
Eric Dumazetefe42082013-10-03 15:42:29 -0700868 sk->sk_v6_daddr = usin->sin6_addr;
David S. Miller4c9483b2011-03-12 16:22:43 -0500869 np->flow_label = fl6.flowlabel;
Gerrit Renker73c9e022006-11-10 13:01:31 -0200870
871 /*
872 * DCCP over IPv4
873 */
874 if (addr_type == IPV6_ADDR_MAPPED) {
875 u32 exthdrlen = icsk->icsk_ext_hdr_len;
876 struct sockaddr_in sin;
877
878 SOCK_DEBUG(sk, "connect: ipv4 mapped\n");
879
880 if (__ipv6_only_sock(sk))
881 return -ENETUNREACH;
882
883 sin.sin_family = AF_INET;
884 sin.sin_port = usin->sin6_port;
885 sin.sin_addr.s_addr = usin->sin6_addr.s6_addr32[3];
886
887 icsk->icsk_af_ops = &dccp_ipv6_mapped;
888 sk->sk_backlog_rcv = dccp_v4_do_rcv;
889
890 err = dccp_v4_connect(sk, (struct sockaddr *)&sin, sizeof(sin));
891 if (err) {
892 icsk->icsk_ext_hdr_len = exthdrlen;
893 icsk->icsk_af_ops = &dccp_ipv6_af_ops;
894 sk->sk_backlog_rcv = dccp_v6_do_rcv;
895 goto failure;
Gerrit Renker73c9e022006-11-10 13:01:31 -0200896 }
Eric Dumazetd1e559d2015-03-18 14:05:35 -0700897 np->saddr = sk->sk_v6_rcv_saddr;
Gerrit Renker73c9e022006-11-10 13:01:31 -0200898 return err;
899 }
900
Eric Dumazetefe42082013-10-03 15:42:29 -0700901 if (!ipv6_addr_any(&sk->sk_v6_rcv_saddr))
902 saddr = &sk->sk_v6_rcv_saddr;
Gerrit Renker73c9e022006-11-10 13:01:31 -0200903
David S. Miller4c9483b2011-03-12 16:22:43 -0500904 fl6.flowi6_proto = IPPROTO_DCCP;
Eric Dumazetefe42082013-10-03 15:42:29 -0700905 fl6.daddr = sk->sk_v6_daddr;
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +0000906 fl6.saddr = saddr ? *saddr : np->saddr;
David S. Miller4c9483b2011-03-12 16:22:43 -0500907 fl6.flowi6_oif = sk->sk_bound_dev_if;
David S. Miller1958b852011-03-12 16:36:19 -0500908 fl6.fl6_dport = usin->sin6_port;
909 fl6.fl6_sport = inet->inet_sport;
David S. Miller4c9483b2011-03-12 16:22:43 -0500910 security_sk_classify_flow(sk, flowi6_to_flowi(&fl6));
Gerrit Renker73c9e022006-11-10 13:01:31 -0200911
Hannes Frederic Sowa1e1d04e2016-04-05 17:10:15 +0200912 opt = rcu_dereference_protected(np->opt, lockdep_sock_is_held(sk));
Eric Dumazet45f6fad2015-11-29 19:37:57 -0800913 final_p = fl6_update_dst(&fl6, opt, &final);
Gerrit Renker73c9e022006-11-10 13:01:31 -0200914
Steffen Klassert0e0d44a2013-08-28 08:04:14 +0200915 dst = ip6_dst_lookup_flow(sk, &fl6, final_p);
David S. Miller68d0c6d2011-03-01 13:19:07 -0800916 if (IS_ERR(dst)) {
917 err = PTR_ERR(dst);
Gerrit Renker73c9e022006-11-10 13:01:31 -0200918 goto failure;
David S. Miller14e50e52007-05-24 18:17:54 -0700919 }
Gerrit Renker73c9e022006-11-10 13:01:31 -0200920
921 if (saddr == NULL) {
David S. Miller4c9483b2011-03-12 16:22:43 -0500922 saddr = &fl6.saddr;
Eric Dumazetefe42082013-10-03 15:42:29 -0700923 sk->sk_v6_rcv_saddr = *saddr;
Gerrit Renker73c9e022006-11-10 13:01:31 -0200924 }
925
926 /* set the source address */
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +0000927 np->saddr = *saddr;
Eric Dumazetc720c7e2009-10-15 06:30:45 +0000928 inet->inet_rcv_saddr = LOOPBACK4_IPV6;
Gerrit Renker73c9e022006-11-10 13:01:31 -0200929
Eric Dumazet6bd4f352015-12-02 21:53:57 -0800930 ip6_dst_store(sk, dst, NULL, NULL);
Gerrit Renker73c9e022006-11-10 13:01:31 -0200931
932 icsk->icsk_ext_hdr_len = 0;
Eric Dumazet45f6fad2015-11-29 19:37:57 -0800933 if (opt)
934 icsk->icsk_ext_hdr_len = opt->opt_flen + opt->opt_nflen;
Gerrit Renker73c9e022006-11-10 13:01:31 -0200935
Eric Dumazetc720c7e2009-10-15 06:30:45 +0000936 inet->inet_dport = usin->sin6_port;
Gerrit Renker73c9e022006-11-10 13:01:31 -0200937
938 dccp_set_state(sk, DCCP_REQUESTING);
939 err = inet6_hash_connect(&dccp_death_row, sk);
940 if (err)
941 goto late_failure;
Gerrit Renkerd7f73652006-11-13 13:34:38 -0200942
943 dp->dccps_iss = secure_dccpv6_sequence_number(np->saddr.s6_addr32,
Eric Dumazetefe42082013-10-03 15:42:29 -0700944 sk->sk_v6_daddr.s6_addr32,
Eric Dumazetc720c7e2009-10-15 06:30:45 +0000945 inet->inet_sport,
946 inet->inet_dport);
Gerrit Renker73c9e022006-11-10 13:01:31 -0200947 err = dccp_connect(sk);
948 if (err)
949 goto late_failure;
950
951 return 0;
952
953late_failure:
954 dccp_set_state(sk, DCCP_CLOSED);
955 __sk_dst_reset(sk);
956failure:
Eric Dumazetc720c7e2009-10-15 06:30:45 +0000957 inet->inet_dport = 0;
Gerrit Renker73c9e022006-11-10 13:01:31 -0200958 sk->sk_route_caps = 0;
959 return err;
960}
961
Stephen Hemminger3b401a82009-09-01 19:25:04 +0000962static const struct inet_connection_sock_af_ops dccp_ipv6_af_ops = {
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -0800963 .queue_xmit = inet6_csk_xmit,
964 .send_check = dccp_v6_send_check,
965 .rebuild_header = inet6_sk_rebuild_header,
966 .conn_request = dccp_v6_conn_request,
967 .syn_recv_sock = dccp_v6_request_recv_sock,
968 .net_header_len = sizeof(struct ipv6hdr),
969 .setsockopt = ipv6_setsockopt,
970 .getsockopt = ipv6_getsockopt,
971 .addr2sockaddr = inet6_csk_addr2sockaddr,
972 .sockaddr_len = sizeof(struct sockaddr_in6),
Dmitry Mishin3fdadf72006-03-20 22:45:21 -0800973#ifdef CONFIG_COMPAT
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -0800974 .compat_setsockopt = compat_ipv6_setsockopt,
975 .compat_getsockopt = compat_ipv6_getsockopt,
Dmitry Mishin3fdadf72006-03-20 22:45:21 -0800976#endif
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800977};
978
979/*
980 * DCCP over IPv4 via INET6 API
981 */
Stephen Hemminger3b401a82009-09-01 19:25:04 +0000982static const struct inet_connection_sock_af_ops dccp_ipv6_mapped = {
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -0800983 .queue_xmit = ip_queue_xmit,
984 .send_check = dccp_v4_send_check,
985 .rebuild_header = inet_sk_rebuild_header,
986 .conn_request = dccp_v6_conn_request,
987 .syn_recv_sock = dccp_v6_request_recv_sock,
988 .net_header_len = sizeof(struct iphdr),
989 .setsockopt = ipv6_setsockopt,
990 .getsockopt = ipv6_getsockopt,
991 .addr2sockaddr = inet6_csk_addr2sockaddr,
992 .sockaddr_len = sizeof(struct sockaddr_in6),
Dmitry Mishin3fdadf72006-03-20 22:45:21 -0800993#ifdef CONFIG_COMPAT
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -0800994 .compat_setsockopt = compat_ipv6_setsockopt,
995 .compat_getsockopt = compat_ipv6_getsockopt,
Dmitry Mishin3fdadf72006-03-20 22:45:21 -0800996#endif
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800997};
998
999/* NOTE: A lot of things set to zero explicitly by call to
1000 * sk_alloc() so need not be done here.
1001 */
1002static int dccp_v6_init_sock(struct sock *sk)
1003{
Arnaldo Carvalho de Melo72478872006-03-20 22:00:37 -08001004 static __u8 dccp_v6_ctl_sock_initialized;
1005 int err = dccp_init_sock(sk, dccp_v6_ctl_sock_initialized);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001006
Arnaldo Carvalho de Melo72478872006-03-20 22:00:37 -08001007 if (err == 0) {
1008 if (unlikely(!dccp_v6_ctl_sock_initialized))
1009 dccp_v6_ctl_sock_initialized = 1;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001010 inet_csk(sk)->icsk_af_ops = &dccp_ipv6_af_ops;
Arnaldo Carvalho de Melo72478872006-03-20 22:00:37 -08001011 }
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001012
1013 return err;
1014}
1015
Brian Haley7d06b2e2008-06-14 17:04:49 -07001016static void dccp_v6_destroy_sock(struct sock *sk)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001017{
Arnaldo Carvalho de Melo3e0fadc2006-03-20 21:23:15 -08001018 dccp_destroy_sock(sk);
Brian Haley7d06b2e2008-06-14 17:04:49 -07001019 inet6_destroy_sock(sk);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001020}
1021
Gerrit Renker73c9e022006-11-10 13:01:31 -02001022static struct timewait_sock_ops dccp6_timewait_sock_ops = {
1023 .twsk_obj_size = sizeof(struct dccp6_timewait_sock),
1024};
1025
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001026static struct proto dccp_v6_prot = {
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001027 .name = "DCCPv6",
1028 .owner = THIS_MODULE,
1029 .close = dccp_close,
1030 .connect = dccp_v6_connect,
1031 .disconnect = dccp_disconnect,
1032 .ioctl = dccp_ioctl,
1033 .init = dccp_v6_init_sock,
1034 .setsockopt = dccp_setsockopt,
1035 .getsockopt = dccp_getsockopt,
1036 .sendmsg = dccp_sendmsg,
1037 .recvmsg = dccp_recvmsg,
1038 .backlog_rcv = dccp_v6_do_rcv,
Craig Gallek496611d2016-02-10 11:50:36 -05001039 .hash = inet6_hash,
Arnaldo Carvalho de Meloab1e0a12008-02-03 04:06:04 -08001040 .unhash = inet_unhash,
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001041 .accept = inet_csk_accept,
Arnaldo Carvalho de Meloab1e0a12008-02-03 04:06:04 -08001042 .get_port = inet_csk_get_port,
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001043 .shutdown = dccp_shutdown,
1044 .destroy = dccp_v6_destroy_sock,
1045 .orphan_count = &dccp_orphan_count,
1046 .max_header = MAX_DCCP_HEADER,
1047 .obj_size = sizeof(struct dccp6_sock),
Paul E. McKenney5f0d5a32017-01-18 02:53:44 -08001048 .slab_flags = SLAB_TYPESAFE_BY_RCU,
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001049 .rsk_prot = &dccp6_request_sock_ops,
1050 .twsk_prot = &dccp6_timewait_sock_ops,
Pavel Emelyanov39d8cda2008-03-22 16:50:58 -07001051 .h.hashinfo = &dccp_hashinfo,
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001052#ifdef CONFIG_COMPAT
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001053 .compat_setsockopt = compat_dccp_setsockopt,
1054 .compat_getsockopt = compat_dccp_getsockopt,
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001055#endif
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001056};
1057
Alexey Dobriyan41135cc2009-09-14 12:22:28 +00001058static const struct inet6_protocol dccp_v6_protocol = {
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -08001059 .handler = dccp_v6_rcv,
1060 .err_handler = dccp_v6_err,
1061 .flags = INET6_PROTO_NOPOLICY | INET6_PROTO_FINAL,
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001062};
1063
Alexey Dobriyan5708e862009-09-14 12:23:23 +00001064static const struct proto_ops inet6_dccp_ops = {
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001065 .family = PF_INET6,
1066 .owner = THIS_MODULE,
1067 .release = inet6_release,
1068 .bind = inet6_bind,
1069 .connect = inet_stream_connect,
1070 .socketpair = sock_no_socketpair,
1071 .accept = inet_accept,
1072 .getname = inet6_getname,
Linus Torvaldsa11e1d42018-06-28 09:43:44 -07001073 .poll = dccp_poll,
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001074 .ioctl = inet6_ioctl,
1075 .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");