blob: 5df7857fc0f3aeefb2ed0324d97d13cb68551383 [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;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800354
Eric Dumazeta2247722014-09-27 09:50:56 -0700355 if (ipv6_opt_accepted(sk, skb, IP6CB(skb)) ||
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800356 np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo ||
357 np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim) {
Reshetova, Elena63354792017-06-30 13:07:58 +0300358 refcount_inc(&skb->users);
Eric Dumazet634fb9792013-10-09 15:21:29 -0700359 ireq->pktopts = skb;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800360 }
Eric Dumazet634fb9792013-10-09 15:21:29 -0700361 ireq->ir_iif = sk->sk_bound_dev_if;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800362
363 /* So that link locals have meaning */
364 if (!sk->sk_bound_dev_if &&
Eric Dumazet634fb9792013-10-09 15:21:29 -0700365 ipv6_addr_type(&ireq->ir_v6_rmt_addr) & IPV6_ADDR_LINKLOCAL)
366 ireq->ir_iif = inet6_iif(skb);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800367
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800368 /*
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800369 * Step 3: Process LISTEN state
370 *
Gerrit Renkerd83ca5a2006-11-10 16:29:14 -0200371 * Set S.ISR, S.GSR, S.SWL, S.SWH from packet or Init Cookie
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800372 *
Samuel Jerof541fb72012-02-26 18:22:02 -0700373 * Setting S.SWL/S.SWH to is deferred to dccp_create_openreq_child().
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800374 */
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800375 dreq->dreq_isr = dcb->dccpd_seq;
Samuel Jerof541fb72012-02-26 18:22:02 -0700376 dreq->dreq_gsr = dreq->dreq_isr;
Gerrit Renker865e9022006-11-13 13:31:50 -0200377 dreq->dreq_iss = dccp_v6_init_sequence(skb);
Samuel Jerof541fb72012-02-26 18:22:02 -0700378 dreq->dreq_gss = dreq->dreq_iss;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800379 dreq->dreq_service = service;
380
Christoph Paasch1a2c6182013-03-17 08:23:34 +0000381 if (dccp_v6_send_response(sk, req))
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800382 goto drop_and_free;
383
Eric Dumazet079096f2015-10-02 11:43:32 -0700384 inet_csk_reqsk_queue_hash_add(sk, req, DCCP_TIMEOUT_INIT);
Xin Long0c2232b2017-07-26 14:19:09 +0800385 reqsk_put(req);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800386 return 0;
387
388drop_and_free:
389 reqsk_free(req);
390drop:
Eric Dumazetaa62d762016-04-27 16:44:28 -0700391 __DCCP_INC_STATS(DCCP_MIB_ATTEMPTFAILS);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800392 return -1;
393}
394
Eric Dumazet0c271712015-09-29 07:42:48 -0700395static struct sock *dccp_v6_request_recv_sock(const struct sock *sk,
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800396 struct sk_buff *skb,
397 struct request_sock *req,
Eric Dumazet5e0724d2015-10-22 08:20:46 -0700398 struct dst_entry *dst,
399 struct request_sock *req_unhash,
400 bool *own_req)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800401{
Eric Dumazet634fb9792013-10-09 15:21:29 -0700402 struct inet_request_sock *ireq = inet_rsk(req);
Eric Dumazet0c271712015-09-29 07:42:48 -0700403 struct ipv6_pinfo *newnp;
404 const struct ipv6_pinfo *np = inet6_sk(sk);
Eric Dumazet45f6fad2015-11-29 19:37:57 -0800405 struct ipv6_txoptions *opt;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800406 struct inet_sock *newinet;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800407 struct dccp6_sock *newdp6;
408 struct sock *newsk;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800409
410 if (skb->protocol == htons(ETH_P_IP)) {
411 /*
412 * v6 mapped
413 */
Eric Dumazet5e0724d2015-10-22 08:20:46 -0700414 newsk = dccp_v4_request_recv_sock(sk, skb, req, dst,
415 req_unhash, own_req);
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800416 if (newsk == NULL)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800417 return NULL;
418
419 newdp6 = (struct dccp6_sock *)newsk;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800420 newinet = inet_sk(newsk);
421 newinet->pinet6 = &newdp6->inet6;
422 newnp = inet6_sk(newsk);
423
424 memcpy(newnp, np, sizeof(struct ipv6_pinfo));
425
Eric Dumazetd1e559d2015-03-18 14:05:35 -0700426 newnp->saddr = newsk->sk_v6_rcv_saddr;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800427
428 inet_csk(newsk)->icsk_af_ops = &dccp_ipv6_mapped;
429 newsk->sk_backlog_rcv = dccp_v4_do_rcv;
430 newnp->pktoptions = NULL;
431 newnp->opt = NULL;
WANG Cong83eadda2017-05-09 16:59:54 -0700432 newnp->ipv6_mc_list = NULL;
433 newnp->ipv6_ac_list = NULL;
434 newnp->ipv6_fl_list = NULL;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800435 newnp->mcast_oif = inet6_iif(skb);
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700436 newnp->mcast_hops = ipv6_hdr(skb)->hop_limit;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800437
438 /*
439 * No need to charge this sock to the relevant IPv6 refcnt debug socks count
440 * here, dccp_create_openreq_child now does this for us, see the comment in
441 * that function for the gory details. -acme
442 */
443
444 /* It is tricky place. Until this moment IPv4 tcp
445 worked with IPv6 icsk.icsk_af_ops.
446 Sync it now.
447 */
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -0800448 dccp_sync_mss(newsk, inet_csk(newsk)->icsk_pmtu_cookie);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800449
450 return newsk;
451 }
452
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800453
454 if (sk_acceptq_is_full(sk))
455 goto out_overflow;
456
Eric Dumazetf76b33c2015-09-29 07:42:42 -0700457 if (!dst) {
David S. Miller4c9483b2011-03-12 16:22:43 -0500458 struct flowi6 fl6;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800459
Eric Dumazetf76b33c2015-09-29 07:42:42 -0700460 dst = inet6_csk_route_req(sk, &fl6, req, IPPROTO_DCCP);
461 if (!dst)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800462 goto out;
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800463 }
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800464
465 newsk = dccp_create_openreq_child(sk, req, skb);
466 if (newsk == NULL)
Balazs Scheidler093d2822010-10-21 13:06:43 +0200467 goto out_nonewsk;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800468
469 /*
470 * No need to charge this sock to the relevant IPv6 refcnt debug socks
471 * count here, dccp_create_openreq_child now does this for us, see the
472 * comment in that function for the gory details. -acme
473 */
474
Eric Dumazet6bd4f352015-12-02 21:53:57 -0800475 ip6_dst_store(newsk, dst, NULL, NULL);
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800476 newsk->sk_route_caps = dst->dev->features & ~(NETIF_F_IP_CSUM |
477 NETIF_F_TSO);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800478 newdp6 = (struct dccp6_sock *)newsk;
479 newinet = inet_sk(newsk);
480 newinet->pinet6 = &newdp6->inet6;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800481 newnp = inet6_sk(newsk);
482
483 memcpy(newnp, np, sizeof(struct ipv6_pinfo));
484
Eric Dumazet634fb9792013-10-09 15:21:29 -0700485 newsk->sk_v6_daddr = ireq->ir_v6_rmt_addr;
486 newnp->saddr = ireq->ir_v6_loc_addr;
487 newsk->sk_v6_rcv_saddr = ireq->ir_v6_loc_addr;
488 newsk->sk_bound_dev_if = ireq->ir_iif;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800489
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800490 /* Now IPv6 options...
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800491
492 First: no IPv4 options.
493 */
Eric Dumazetf6d8bd02011-04-21 09:45:37 +0000494 newinet->inet_opt = NULL;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800495
496 /* Clone RX bits */
497 newnp->rxopt.all = np->rxopt.all;
498
WANG Cong83eadda2017-05-09 16:59:54 -0700499 newnp->ipv6_mc_list = NULL;
500 newnp->ipv6_ac_list = NULL;
501 newnp->ipv6_fl_list = NULL;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800502 newnp->pktoptions = NULL;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800503 newnp->opt = NULL;
504 newnp->mcast_oif = inet6_iif(skb);
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700505 newnp->mcast_hops = ipv6_hdr(skb)->hop_limit;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800506
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800507 /*
508 * Clone native IPv6 options from listening socket (if any)
509 *
510 * Yes, keeping reference count would be much more clever, but we make
511 * one more one thing there: reattach optmem to newsk.
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800512 */
Huw Davies56ac42b2016-06-27 15:05:28 -0400513 opt = ireq->ipv6_opt;
514 if (!opt)
515 opt = rcu_dereference(np->opt);
Eric Dumazet45f6fad2015-11-29 19:37:57 -0800516 if (opt) {
517 opt = ipv6_dup_options(newsk, opt);
518 RCU_INIT_POINTER(newnp->opt, opt);
519 }
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -0800520 inet_csk(newsk)->icsk_ext_hdr_len = 0;
Eric Dumazet45f6fad2015-11-29 19:37:57 -0800521 if (opt)
522 inet_csk(newsk)->icsk_ext_hdr_len = opt->opt_nflen +
523 opt->opt_flen;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800524
525 dccp_sync_mss(newsk, dst_mtu(dst));
526
Eric Dumazetc720c7e2009-10-15 06:30:45 +0000527 newinet->inet_daddr = newinet->inet_saddr = LOOPBACK4_IPV6;
528 newinet->inet_rcv_saddr = LOOPBACK4_IPV6;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800529
Balazs Scheidler093d2822010-10-21 13:06:43 +0200530 if (__inet_inherit_port(sk, newsk) < 0) {
Christoph Paasche337e242012-12-14 04:07:58 +0000531 inet_csk_prepare_forced_close(newsk);
532 dccp_done(newsk);
Balazs Scheidler093d2822010-10-21 13:06:43 +0200533 goto out;
534 }
Eric Dumazet5e0724d2015-10-22 08:20:46 -0700535 *own_req = inet_ehash_nolisten(newsk, req_to_sk(req_unhash));
Eric Dumazetce105002015-10-30 09:46:12 -0700536 /* Clone pktoptions received with SYN, if we own the req */
537 if (*own_req && ireq->pktopts) {
538 newnp->pktoptions = skb_clone(ireq->pktopts, GFP_ATOMIC);
539 consume_skb(ireq->pktopts);
540 ireq->pktopts = NULL;
541 if (newnp->pktoptions)
542 skb_set_owner_r(newnp->pktoptions, newsk);
543 }
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800544
545 return newsk;
546
547out_overflow:
Eric Dumazet02a1d6e2016-04-27 16:44:39 -0700548 __NET_INC_STATS(sock_net(sk), LINUX_MIB_LISTENOVERFLOWS);
Balazs Scheidler093d2822010-10-21 13:06:43 +0200549out_nonewsk:
550 dst_release(dst);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800551out:
Eric Dumazet02a1d6e2016-04-27 16:44:39 -0700552 __NET_INC_STATS(sock_net(sk), LINUX_MIB_LISTENDROPS);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800553 return NULL;
554}
555
556/* The socket must have it's spinlock held when we get
557 * here.
558 *
559 * We have a potential double-lock case here, so even when
560 * doing backlog processing we use the BH locking scheme.
561 * This is because we cannot sleep with the original spinlock
562 * held.
563 */
564static int dccp_v6_do_rcv(struct sock *sk, struct sk_buff *skb)
565{
566 struct ipv6_pinfo *np = inet6_sk(sk);
567 struct sk_buff *opt_skb = NULL;
568
569 /* Imagine: socket is IPv6. IPv4 packet arrives,
570 goes to IPv4 receive handler and backlogged.
571 From backlog it always goes here. Kerboom...
572 Fortunately, dccp_rcv_established and rcv_established
573 handle them correctly, but it is not case with
574 dccp_v6_hnd_req and dccp_v6_ctl_send_reset(). --ANK
575 */
576
577 if (skb->protocol == htons(ETH_P_IP))
578 return dccp_v4_do_rcv(sk, skb);
579
Dmitry Mishinfda9ef52006-08-31 15:28:39 -0700580 if (sk_filter(sk, skb))
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800581 goto discard;
582
583 /*
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800584 * socket locking is here for SMP purposes as backlog rcv is currently
585 * called with bh processing disabled.
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800586 */
587
588 /* Do Stevens' IPV6_PKTOPTIONS.
589
590 Yes, guys, it is the only place in our code, where we
591 may make it not affecting IPv4.
592 The rest of code is protocol independent,
593 and I do not like idea to uglify IPv4.
594
595 Actually, all the idea behind IPV6_PKTOPTIONS
596 looks not very well thought. For now we latch
597 options, received in the last packet, enqueued
598 by tcp. Feel free to propose better solution.
YOSHIFUJI Hideakic9eaf172007-02-09 23:24:38 +0900599 --ANK (980728)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800600 */
601 if (np->rxopt.all)
602 opt_skb = skb_clone(skb, GFP_ATOMIC);
603
604 if (sk->sk_state == DCCP_OPEN) { /* Fast path */
605 if (dccp_rcv_established(sk, skb, dccp_hdr(skb), skb->len))
606 goto reset;
Andrii323fbd02017-08-31 08:28:01 +0300607 if (opt_skb)
608 goto ipv6_pktoptions;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800609 return 0;
610 }
611
Gerrit Renkerd83ca5a2006-11-10 16:29:14 -0200612 /*
613 * Step 3: Process LISTEN state
614 * If S.state == LISTEN,
615 * If P.type == Request or P contains a valid Init Cookie option,
616 * (* Must scan the packet's options to check for Init
617 * Cookies. Only Init Cookies are processed here,
618 * however; other options are processed in Step 8. This
619 * scan need only be performed if the endpoint uses Init
620 * Cookies *)
621 * (* Generate a new socket and switch to that socket *)
622 * Set S := new socket for this port pair
623 * S.state = RESPOND
624 * Choose S.ISS (initial seqno) or set from Init Cookies
625 * Initialize S.GAR := S.ISS
626 * Set S.ISR, S.GSR, S.SWL, S.SWH from packet or Init Cookies
627 * Continue with S.state == RESPOND
628 * (* A Response packet will be generated in Step 11 *)
629 * Otherwise,
630 * Generate Reset(No Connection) unless P.type == Reset
631 * Drop packet and return
632 *
633 * NOTE: the check for the packet types is done in
634 * dccp_rcv_state_process
635 */
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800636
637 if (dccp_rcv_state_process(sk, skb, dccp_hdr(skb), skb->len))
638 goto reset;
Andrii323fbd02017-08-31 08:28:01 +0300639 if (opt_skb)
640 goto ipv6_pktoptions;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800641 return 0;
642
643reset:
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800644 dccp_v6_ctl_send_reset(sk, skb);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800645discard:
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800646 if (opt_skb != NULL)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800647 __kfree_skb(opt_skb);
648 kfree_skb(skb);
649 return 0;
Andrii323fbd02017-08-31 08:28:01 +0300650
651/* Handling IPV6_PKTOPTIONS skb the similar
652 * way it's done for net/ipv6/tcp_ipv6.c
653 */
654ipv6_pktoptions:
655 if (!((1 << sk->sk_state) & (DCCPF_CLOSED | DCCPF_LISTEN))) {
656 if (np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo)
657 np->mcast_oif = inet6_iif(opt_skb);
658 if (np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim)
659 np->mcast_hops = ipv6_hdr(opt_skb)->hop_limit;
660 if (np->rxopt.bits.rxflow || np->rxopt.bits.rxtclass)
661 np->rcv_flowinfo = ip6_flowinfo(ipv6_hdr(opt_skb));
662 if (np->repflow)
663 np->flow_label = ip6_flowlabel(ipv6_hdr(opt_skb));
664 if (ipv6_opt_accepted(sk, opt_skb,
665 &DCCP_SKB_CB(opt_skb)->header.h6)) {
666 skb_set_owner_r(opt_skb, sk);
667 memmove(IP6CB(opt_skb),
668 &DCCP_SKB_CB(opt_skb)->header.h6,
669 sizeof(struct inet6_skb_parm));
670 opt_skb = xchg(&np->pktoptions, opt_skb);
671 } else {
672 __kfree_skb(opt_skb);
673 opt_skb = xchg(&np->pktoptions, NULL);
674 }
675 }
676
677 kfree_skb(opt_skb);
678 return 0;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800679}
680
Herbert Xue5bbef22007-10-15 12:50:28 -0700681static int dccp_v6_rcv(struct sk_buff *skb)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800682{
683 const struct dccp_hdr *dh;
Eric Dumazet3b24d852016-04-01 08:52:17 -0700684 bool refcounted;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800685 struct sock *sk;
Gerrit Renker6f4e5ff2006-11-10 17:43:06 -0200686 int min_cov;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800687
Gerrit Renker6f4e5ff2006-11-10 17:43:06 -0200688 /* Step 1: Check header basics */
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800689
690 if (dccp_invalid_packet(skb))
691 goto discard_it;
692
Gerrit Renker6f4e5ff2006-11-10 17:43:06 -0200693 /* Step 1: If header checksum is incorrect, drop packet and return. */
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700694 if (dccp_v6_csum_finish(skb, &ipv6_hdr(skb)->saddr,
695 &ipv6_hdr(skb)->daddr)) {
Gerrit Renker59348b12006-11-20 18:39:23 -0200696 DCCP_WARN("dropped packet with invalid checksum\n");
Gerrit Renker6f4e5ff2006-11-10 17:43:06 -0200697 goto discard_it;
698 }
699
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800700 dh = dccp_hdr(skb);
701
Gerrit Renkerfde20102007-10-24 10:12:09 -0200702 DCCP_SKB_CB(skb)->dccpd_seq = dccp_hdr_seq(dh);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800703 DCCP_SKB_CB(skb)->dccpd_type = dh->dccph_type;
704
705 if (dccp_packet_without_ack(skb))
706 DCCP_SKB_CB(skb)->dccpd_ack_seq = DCCP_PKT_WITHOUT_ACK_SEQ;
707 else
708 DCCP_SKB_CB(skb)->dccpd_ack_seq = dccp_hdr_ack_seq(skb);
709
Eric Dumazet4bdc3d62015-10-13 17:12:54 -0700710lookup:
Craig Galleka5836362016-02-10 11:50:38 -0500711 sk = __inet6_lookup_skb(&dccp_hashinfo, skb, __dccp_hdr_len(dh),
Eric Dumazet870c3152014-10-17 09:17:20 -0700712 dh->dccph_sport, dh->dccph_dport,
David Ahern4297a0e2017-08-07 08:44:21 -0700713 inet6_iif(skb), 0, &refcounted);
Eric Dumazet4bdc3d62015-10-13 17:12:54 -0700714 if (!sk) {
Gerrit Renkerd23c7102006-11-10 11:46:34 -0200715 dccp_pr_debug("failed to look up flow ID in table and "
716 "get corresponding socket\n");
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800717 goto no_dccp_socket;
Gerrit Renkerd23c7102006-11-10 11:46:34 -0200718 }
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800719
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800720 /*
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800721 * Step 2:
Arnaldo Carvalho de Melo8109b022006-12-10 16:01:18 -0200722 * ... or S.state == TIMEWAIT,
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800723 * Generate Reset(No Connection) unless P.type == Reset
724 * Drop packet and return
725 */
Gerrit Renkerd23c7102006-11-10 11:46:34 -0200726 if (sk->sk_state == DCCP_TIME_WAIT) {
727 dccp_pr_debug("sk->sk_state == DCCP_TIME_WAIT: do_time_wait\n");
728 inet_twsk_put(inet_twsk(sk));
729 goto no_dccp_socket;
730 }
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800731
Eric Dumazet079096f2015-10-02 11:43:32 -0700732 if (sk->sk_state == DCCP_NEW_SYN_RECV) {
733 struct request_sock *req = inet_reqsk(sk);
Eric Dumazet77166822016-02-18 05:39:18 -0800734 struct sock *nsk;
Eric Dumazet079096f2015-10-02 11:43:32 -0700735
736 sk = req->rsk_listener;
Eric Dumazet77166822016-02-18 05:39:18 -0800737 if (unlikely(sk->sk_state != DCCP_LISTEN)) {
Eric Dumazetf03f2e12015-10-14 11:16:27 -0700738 inet_csk_reqsk_queue_drop_and_put(sk, req);
Eric Dumazet4bdc3d62015-10-13 17:12:54 -0700739 goto lookup;
740 }
Eric Dumazet77166822016-02-18 05:39:18 -0800741 sock_hold(sk);
Eric Dumazet3b24d852016-04-01 08:52:17 -0700742 refcounted = true;
Eric Dumazet77166822016-02-18 05:39:18 -0800743 nsk = dccp_check_req(sk, skb, req);
Eric Dumazet079096f2015-10-02 11:43:32 -0700744 if (!nsk) {
745 reqsk_put(req);
Eric Dumazet77166822016-02-18 05:39:18 -0800746 goto discard_and_relse;
Eric Dumazet079096f2015-10-02 11:43:32 -0700747 }
748 if (nsk == sk) {
Eric Dumazet079096f2015-10-02 11:43:32 -0700749 reqsk_put(req);
750 } else if (dccp_child_process(sk, nsk, skb)) {
751 dccp_v6_ctl_send_reset(sk, skb);
Eric Dumazet77166822016-02-18 05:39:18 -0800752 goto discard_and_relse;
Eric Dumazet079096f2015-10-02 11:43:32 -0700753 } else {
Eric Dumazet77166822016-02-18 05:39:18 -0800754 sock_put(sk);
Eric Dumazet079096f2015-10-02 11:43:32 -0700755 return 0;
756 }
757 }
Gerrit Renker6f4e5ff2006-11-10 17:43:06 -0200758 /*
759 * RFC 4340, sec. 9.2.1: Minimum Checksum Coverage
Arnaldo Carvalho de Melo8109b022006-12-10 16:01:18 -0200760 * o if MinCsCov = 0, only packets with CsCov = 0 are accepted
761 * o if MinCsCov > 0, also accept packets with CsCov >= MinCsCov
Gerrit Renker6f4e5ff2006-11-10 17:43:06 -0200762 */
763 min_cov = dccp_sk(sk)->dccps_pcrlen;
764 if (dh->dccph_cscov && (min_cov == 0 || dh->dccph_cscov < min_cov)) {
765 dccp_pr_debug("Packet CsCov %d does not satisfy MinCsCov %d\n",
766 dh->dccph_cscov, min_cov);
767 /* FIXME: send Data Dropped option (see also dccp_v4_rcv) */
768 goto discard_and_relse;
769 }
770
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800771 if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb))
772 goto discard_and_relse;
773
Eric Dumazetc3f24cf2016-11-02 17:14:41 -0700774 return __sk_receive_skb(sk, skb, 1, dh->dccph_doff * 4,
775 refcounted) ? -1 : 0;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800776
777no_dccp_socket:
778 if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb))
779 goto discard_it;
780 /*
781 * Step 2:
Arnaldo Carvalho de Melo8109b022006-12-10 16:01:18 -0200782 * If no socket ...
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800783 * Generate Reset(No Connection) unless P.type == Reset
784 * Drop packet and return
785 */
786 if (dh->dccph_type != DCCP_PKT_RESET) {
787 DCCP_SKB_CB(skb)->dccpd_reset_code =
788 DCCP_RESET_CODE_NO_CONNECTION;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800789 dccp_v6_ctl_send_reset(sk, skb);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800790 }
Gerrit Renkerd23c7102006-11-10 11:46:34 -0200791
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800792discard_it:
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800793 kfree_skb(skb);
794 return 0;
795
796discard_and_relse:
Eric Dumazet3b24d852016-04-01 08:52:17 -0700797 if (refcounted)
798 sock_put(sk);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800799 goto discard_it;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800800}
801
Gerrit Renker73c9e022006-11-10 13:01:31 -0200802static int dccp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
803 int addr_len)
804{
805 struct sockaddr_in6 *usin = (struct sockaddr_in6 *)uaddr;
806 struct inet_connection_sock *icsk = inet_csk(sk);
807 struct inet_sock *inet = inet_sk(sk);
808 struct ipv6_pinfo *np = inet6_sk(sk);
809 struct dccp_sock *dp = dccp_sk(sk);
Arnaud Ebalard20c59de2010-06-01 21:35:01 +0000810 struct in6_addr *saddr = NULL, *final_p, final;
Eric Dumazet45f6fad2015-11-29 19:37:57 -0800811 struct ipv6_txoptions *opt;
David S. Miller4c9483b2011-03-12 16:22:43 -0500812 struct flowi6 fl6;
Gerrit Renker73c9e022006-11-10 13:01:31 -0200813 struct dst_entry *dst;
814 int addr_type;
815 int err;
816
817 dp->dccps_role = DCCP_ROLE_CLIENT;
818
819 if (addr_len < SIN6_LEN_RFC2133)
820 return -EINVAL;
821
822 if (usin->sin6_family != AF_INET6)
823 return -EAFNOSUPPORT;
824
David S. Miller4c9483b2011-03-12 16:22:43 -0500825 memset(&fl6, 0, sizeof(fl6));
Gerrit Renker73c9e022006-11-10 13:01:31 -0200826
827 if (np->sndflow) {
David S. Miller4c9483b2011-03-12 16:22:43 -0500828 fl6.flowlabel = usin->sin6_flowinfo & IPV6_FLOWINFO_MASK;
829 IP6_ECN_flow_init(fl6.flowlabel);
830 if (fl6.flowlabel & IPV6_FLOWLABEL_MASK) {
Gerrit Renker73c9e022006-11-10 13:01:31 -0200831 struct ip6_flowlabel *flowlabel;
David S. Miller4c9483b2011-03-12 16:22:43 -0500832 flowlabel = fl6_sock_lookup(sk, fl6.flowlabel);
Gerrit Renker73c9e022006-11-10 13:01:31 -0200833 if (flowlabel == NULL)
834 return -EINVAL;
Gerrit Renker73c9e022006-11-10 13:01:31 -0200835 fl6_sock_release(flowlabel);
836 }
837 }
838 /*
839 * connect() to INADDR_ANY means loopback (BSD'ism).
840 */
841 if (ipv6_addr_any(&usin->sin6_addr))
842 usin->sin6_addr.s6_addr[15] = 1;
843
844 addr_type = ipv6_addr_type(&usin->sin6_addr);
845
846 if (addr_type & IPV6_ADDR_MULTICAST)
847 return -ENETUNREACH;
848
849 if (addr_type & IPV6_ADDR_LINKLOCAL) {
850 if (addr_len >= sizeof(struct sockaddr_in6) &&
851 usin->sin6_scope_id) {
852 /* If interface is set while binding, indices
853 * must coincide.
854 */
855 if (sk->sk_bound_dev_if &&
856 sk->sk_bound_dev_if != usin->sin6_scope_id)
857 return -EINVAL;
858
859 sk->sk_bound_dev_if = usin->sin6_scope_id;
860 }
861
862 /* Connect to link-local address requires an interface */
863 if (!sk->sk_bound_dev_if)
864 return -EINVAL;
865 }
866
Eric Dumazetefe42082013-10-03 15:42:29 -0700867 sk->sk_v6_daddr = usin->sin6_addr;
David S. Miller4c9483b2011-03-12 16:22:43 -0500868 np->flow_label = fl6.flowlabel;
Gerrit Renker73c9e022006-11-10 13:01:31 -0200869
870 /*
871 * DCCP over IPv4
872 */
873 if (addr_type == IPV6_ADDR_MAPPED) {
874 u32 exthdrlen = icsk->icsk_ext_hdr_len;
875 struct sockaddr_in sin;
876
877 SOCK_DEBUG(sk, "connect: ipv4 mapped\n");
878
879 if (__ipv6_only_sock(sk))
880 return -ENETUNREACH;
881
882 sin.sin_family = AF_INET;
883 sin.sin_port = usin->sin6_port;
884 sin.sin_addr.s_addr = usin->sin6_addr.s6_addr32[3];
885
886 icsk->icsk_af_ops = &dccp_ipv6_mapped;
887 sk->sk_backlog_rcv = dccp_v4_do_rcv;
888
889 err = dccp_v4_connect(sk, (struct sockaddr *)&sin, sizeof(sin));
890 if (err) {
891 icsk->icsk_ext_hdr_len = exthdrlen;
892 icsk->icsk_af_ops = &dccp_ipv6_af_ops;
893 sk->sk_backlog_rcv = dccp_v6_do_rcv;
894 goto failure;
Gerrit Renker73c9e022006-11-10 13:01:31 -0200895 }
Eric Dumazetd1e559d2015-03-18 14:05:35 -0700896 np->saddr = sk->sk_v6_rcv_saddr;
Gerrit Renker73c9e022006-11-10 13:01:31 -0200897 return err;
898 }
899
Eric Dumazetefe42082013-10-03 15:42:29 -0700900 if (!ipv6_addr_any(&sk->sk_v6_rcv_saddr))
901 saddr = &sk->sk_v6_rcv_saddr;
Gerrit Renker73c9e022006-11-10 13:01:31 -0200902
David S. Miller4c9483b2011-03-12 16:22:43 -0500903 fl6.flowi6_proto = IPPROTO_DCCP;
Eric Dumazetefe42082013-10-03 15:42:29 -0700904 fl6.daddr = sk->sk_v6_daddr;
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +0000905 fl6.saddr = saddr ? *saddr : np->saddr;
David S. Miller4c9483b2011-03-12 16:22:43 -0500906 fl6.flowi6_oif = sk->sk_bound_dev_if;
David S. Miller1958b852011-03-12 16:36:19 -0500907 fl6.fl6_dport = usin->sin6_port;
908 fl6.fl6_sport = inet->inet_sport;
David S. Miller4c9483b2011-03-12 16:22:43 -0500909 security_sk_classify_flow(sk, flowi6_to_flowi(&fl6));
Gerrit Renker73c9e022006-11-10 13:01:31 -0200910
Hannes Frederic Sowa1e1d04e2016-04-05 17:10:15 +0200911 opt = rcu_dereference_protected(np->opt, lockdep_sock_is_held(sk));
Eric Dumazet45f6fad2015-11-29 19:37:57 -0800912 final_p = fl6_update_dst(&fl6, opt, &final);
Gerrit Renker73c9e022006-11-10 13:01:31 -0200913
Steffen Klassert0e0d44a2013-08-28 08:04:14 +0200914 dst = ip6_dst_lookup_flow(sk, &fl6, final_p);
David S. Miller68d0c6d2011-03-01 13:19:07 -0800915 if (IS_ERR(dst)) {
916 err = PTR_ERR(dst);
Gerrit Renker73c9e022006-11-10 13:01:31 -0200917 goto failure;
David S. Miller14e50e52007-05-24 18:17:54 -0700918 }
Gerrit Renker73c9e022006-11-10 13:01:31 -0200919
920 if (saddr == NULL) {
David S. Miller4c9483b2011-03-12 16:22:43 -0500921 saddr = &fl6.saddr;
Eric Dumazetefe42082013-10-03 15:42:29 -0700922 sk->sk_v6_rcv_saddr = *saddr;
Gerrit Renker73c9e022006-11-10 13:01:31 -0200923 }
924
925 /* set the source address */
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +0000926 np->saddr = *saddr;
Eric Dumazetc720c7e2009-10-15 06:30:45 +0000927 inet->inet_rcv_saddr = LOOPBACK4_IPV6;
Gerrit Renker73c9e022006-11-10 13:01:31 -0200928
Eric Dumazet6bd4f352015-12-02 21:53:57 -0800929 ip6_dst_store(sk, dst, NULL, NULL);
Gerrit Renker73c9e022006-11-10 13:01:31 -0200930
931 icsk->icsk_ext_hdr_len = 0;
Eric Dumazet45f6fad2015-11-29 19:37:57 -0800932 if (opt)
933 icsk->icsk_ext_hdr_len = opt->opt_flen + opt->opt_nflen;
Gerrit Renker73c9e022006-11-10 13:01:31 -0200934
Eric Dumazetc720c7e2009-10-15 06:30:45 +0000935 inet->inet_dport = usin->sin6_port;
Gerrit Renker73c9e022006-11-10 13:01:31 -0200936
937 dccp_set_state(sk, DCCP_REQUESTING);
938 err = inet6_hash_connect(&dccp_death_row, sk);
939 if (err)
940 goto late_failure;
Gerrit Renkerd7f73652006-11-13 13:34:38 -0200941
942 dp->dccps_iss = secure_dccpv6_sequence_number(np->saddr.s6_addr32,
Eric Dumazetefe42082013-10-03 15:42:29 -0700943 sk->sk_v6_daddr.s6_addr32,
Eric Dumazetc720c7e2009-10-15 06:30:45 +0000944 inet->inet_sport,
945 inet->inet_dport);
Gerrit Renker73c9e022006-11-10 13:01:31 -0200946 err = dccp_connect(sk);
947 if (err)
948 goto late_failure;
949
950 return 0;
951
952late_failure:
953 dccp_set_state(sk, DCCP_CLOSED);
954 __sk_dst_reset(sk);
955failure:
Eric Dumazetc720c7e2009-10-15 06:30:45 +0000956 inet->inet_dport = 0;
Gerrit Renker73c9e022006-11-10 13:01:31 -0200957 sk->sk_route_caps = 0;
958 return err;
959}
960
Stephen Hemminger3b401a82009-09-01 19:25:04 +0000961static const struct inet_connection_sock_af_ops dccp_ipv6_af_ops = {
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -0800962 .queue_xmit = inet6_csk_xmit,
963 .send_check = dccp_v6_send_check,
964 .rebuild_header = inet6_sk_rebuild_header,
965 .conn_request = dccp_v6_conn_request,
966 .syn_recv_sock = dccp_v6_request_recv_sock,
967 .net_header_len = sizeof(struct ipv6hdr),
968 .setsockopt = ipv6_setsockopt,
969 .getsockopt = ipv6_getsockopt,
970 .addr2sockaddr = inet6_csk_addr2sockaddr,
971 .sockaddr_len = sizeof(struct sockaddr_in6),
Dmitry Mishin3fdadf72006-03-20 22:45:21 -0800972#ifdef CONFIG_COMPAT
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -0800973 .compat_setsockopt = compat_ipv6_setsockopt,
974 .compat_getsockopt = compat_ipv6_getsockopt,
Dmitry Mishin3fdadf72006-03-20 22:45:21 -0800975#endif
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800976};
977
978/*
979 * DCCP over IPv4 via INET6 API
980 */
Stephen Hemminger3b401a82009-09-01 19:25:04 +0000981static const struct inet_connection_sock_af_ops dccp_ipv6_mapped = {
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -0800982 .queue_xmit = ip_queue_xmit,
983 .send_check = dccp_v4_send_check,
984 .rebuild_header = inet_sk_rebuild_header,
985 .conn_request = dccp_v6_conn_request,
986 .syn_recv_sock = dccp_v6_request_recv_sock,
987 .net_header_len = sizeof(struct iphdr),
988 .setsockopt = ipv6_setsockopt,
989 .getsockopt = ipv6_getsockopt,
990 .addr2sockaddr = inet6_csk_addr2sockaddr,
991 .sockaddr_len = sizeof(struct sockaddr_in6),
Dmitry Mishin3fdadf72006-03-20 22:45:21 -0800992#ifdef CONFIG_COMPAT
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -0800993 .compat_setsockopt = compat_ipv6_setsockopt,
994 .compat_getsockopt = compat_ipv6_getsockopt,
Dmitry Mishin3fdadf72006-03-20 22:45:21 -0800995#endif
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800996};
997
998/* NOTE: A lot of things set to zero explicitly by call to
999 * sk_alloc() so need not be done here.
1000 */
1001static int dccp_v6_init_sock(struct sock *sk)
1002{
Arnaldo Carvalho de Melo72478872006-03-20 22:00:37 -08001003 static __u8 dccp_v6_ctl_sock_initialized;
1004 int err = dccp_init_sock(sk, dccp_v6_ctl_sock_initialized);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001005
Arnaldo Carvalho de Melo72478872006-03-20 22:00:37 -08001006 if (err == 0) {
1007 if (unlikely(!dccp_v6_ctl_sock_initialized))
1008 dccp_v6_ctl_sock_initialized = 1;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001009 inet_csk(sk)->icsk_af_ops = &dccp_ipv6_af_ops;
Arnaldo Carvalho de Melo72478872006-03-20 22:00:37 -08001010 }
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001011
1012 return err;
1013}
1014
Brian Haley7d06b2e2008-06-14 17:04:49 -07001015static void dccp_v6_destroy_sock(struct sock *sk)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001016{
Arnaldo Carvalho de Melo3e0fadc2006-03-20 21:23:15 -08001017 dccp_destroy_sock(sk);
Brian Haley7d06b2e2008-06-14 17:04:49 -07001018 inet6_destroy_sock(sk);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001019}
1020
Gerrit Renker73c9e022006-11-10 13:01:31 -02001021static struct timewait_sock_ops dccp6_timewait_sock_ops = {
1022 .twsk_obj_size = sizeof(struct dccp6_timewait_sock),
1023};
1024
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001025static struct proto dccp_v6_prot = {
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001026 .name = "DCCPv6",
1027 .owner = THIS_MODULE,
1028 .close = dccp_close,
1029 .connect = dccp_v6_connect,
1030 .disconnect = dccp_disconnect,
1031 .ioctl = dccp_ioctl,
1032 .init = dccp_v6_init_sock,
1033 .setsockopt = dccp_setsockopt,
1034 .getsockopt = dccp_getsockopt,
1035 .sendmsg = dccp_sendmsg,
1036 .recvmsg = dccp_recvmsg,
1037 .backlog_rcv = dccp_v6_do_rcv,
Craig Gallek496611d2016-02-10 11:50:36 -05001038 .hash = inet6_hash,
Arnaldo Carvalho de Meloab1e0a12008-02-03 04:06:04 -08001039 .unhash = inet_unhash,
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001040 .accept = inet_csk_accept,
Arnaldo Carvalho de Meloab1e0a12008-02-03 04:06:04 -08001041 .get_port = inet_csk_get_port,
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001042 .shutdown = dccp_shutdown,
1043 .destroy = dccp_v6_destroy_sock,
1044 .orphan_count = &dccp_orphan_count,
1045 .max_header = MAX_DCCP_HEADER,
1046 .obj_size = sizeof(struct dccp6_sock),
Paul E. McKenney5f0d5a32017-01-18 02:53:44 -08001047 .slab_flags = SLAB_TYPESAFE_BY_RCU,
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001048 .rsk_prot = &dccp6_request_sock_ops,
1049 .twsk_prot = &dccp6_timewait_sock_ops,
Pavel Emelyanov39d8cda2008-03-22 16:50:58 -07001050 .h.hashinfo = &dccp_hashinfo,
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001051#ifdef CONFIG_COMPAT
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001052 .compat_setsockopt = compat_dccp_setsockopt,
1053 .compat_getsockopt = compat_dccp_getsockopt,
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001054#endif
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001055};
1056
Alexey Dobriyan41135cc2009-09-14 12:22:28 +00001057static const struct inet6_protocol dccp_v6_protocol = {
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -08001058 .handler = dccp_v6_rcv,
1059 .err_handler = dccp_v6_err,
1060 .flags = INET6_PROTO_NOPOLICY | INET6_PROTO_FINAL,
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001061};
1062
Alexey Dobriyan5708e862009-09-14 12:23:23 +00001063static const struct proto_ops inet6_dccp_ops = {
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001064 .family = PF_INET6,
1065 .owner = THIS_MODULE,
1066 .release = inet6_release,
1067 .bind = inet6_bind,
1068 .connect = inet_stream_connect,
1069 .socketpair = sock_no_socketpair,
1070 .accept = inet_accept,
1071 .getname = inet6_getname,
1072 .poll = dccp_poll,
1073 .ioctl = inet6_ioctl,
1074 .listen = inet_dccp_listen,
1075 .shutdown = inet_shutdown,
1076 .setsockopt = sock_common_setsockopt,
1077 .getsockopt = sock_common_getsockopt,
1078 .sendmsg = inet_sendmsg,
1079 .recvmsg = sock_common_recvmsg,
1080 .mmap = sock_no_mmap,
1081 .sendpage = sock_no_sendpage,
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001082#ifdef CONFIG_COMPAT
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001083 .compat_setsockopt = compat_sock_common_setsockopt,
1084 .compat_getsockopt = compat_sock_common_getsockopt,
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001085#endif
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001086};
1087
1088static struct inet_protosw dccp_v6_protosw = {
1089 .type = SOCK_DCCP,
1090 .protocol = IPPROTO_DCCP,
1091 .prot = &dccp_v6_prot,
1092 .ops = &inet6_dccp_ops,
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -08001093 .flags = INET_PROTOSW_ICSK,
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001094};
1095
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00001096static int __net_init dccp_v6_init_net(struct net *net)
Pavel Emelyanov8231bd22008-04-13 22:32:02 -07001097{
Gerrit Renkerd14a0eb2010-03-14 20:13:19 +00001098 if (dccp_hashinfo.bhash == NULL)
1099 return -ESOCKTNOSUPPORT;
Pavel Emelyanov334527d2008-04-13 22:32:45 -07001100
Gerrit Renkerd14a0eb2010-03-14 20:13:19 +00001101 return inet_ctl_sock_create(&net->dccp.v6_ctl_sk, PF_INET6,
1102 SOCK_DCCP, IPPROTO_DCCP, net);
Pavel Emelyanov8231bd22008-04-13 22:32:02 -07001103}
1104
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00001105static void __net_exit dccp_v6_exit_net(struct net *net)
Pavel Emelyanov8231bd22008-04-13 22:32:02 -07001106{
Pavel Emelyanov334527d2008-04-13 22:32:45 -07001107 inet_ctl_sock_destroy(net->dccp.v6_ctl_sk);
Pavel Emelyanov8231bd22008-04-13 22:32:02 -07001108}
1109
Andrey Ryabininec7cb622017-02-22 12:35:27 +03001110static void __net_exit dccp_v6_exit_batch(struct list_head *net_exit_list)
1111{
1112 inet_twsk_purge(&dccp_hashinfo, AF_INET6);
1113}
1114
Pavel Emelyanov8231bd22008-04-13 22:32:02 -07001115static struct pernet_operations dccp_v6_ops = {
1116 .init = dccp_v6_init_net,
1117 .exit = dccp_v6_exit_net,
Andrey Ryabininec7cb622017-02-22 12:35:27 +03001118 .exit_batch = dccp_v6_exit_batch,
Pavel Emelyanov8231bd22008-04-13 22:32:02 -07001119};
1120
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001121static int __init dccp_v6_init(void)
1122{
1123 int err = proto_register(&dccp_v6_prot, 1);
1124
Xin Longa0f9a4c2017-06-20 15:44:44 +08001125 if (err)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001126 goto out;
1127
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001128 inet6_register_protosw(&dccp_v6_protosw);
Arnaldo Carvalho de Melo72478872006-03-20 22:00:37 -08001129
Pavel Emelyanov8231bd22008-04-13 22:32:02 -07001130 err = register_pernet_subsys(&dccp_v6_ops);
Xin Longa0f9a4c2017-06-20 15:44:44 +08001131 if (err)
Pavel Emelyanov8231bd22008-04-13 22:32:02 -07001132 goto out_destroy_ctl_sock;
Xin Longa0f9a4c2017-06-20 15:44:44 +08001133
1134 err = inet6_add_protocol(&dccp_v6_protocol, IPPROTO_DCCP);
1135 if (err)
1136 goto out_unregister_proto;
1137
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001138out:
1139 return err;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001140out_unregister_proto:
Xin Longa0f9a4c2017-06-20 15:44:44 +08001141 unregister_pernet_subsys(&dccp_v6_ops);
1142out_destroy_ctl_sock:
1143 inet6_unregister_protosw(&dccp_v6_protosw);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001144 proto_unregister(&dccp_v6_prot);
1145 goto out;
1146}
1147
1148static void __exit dccp_v6_exit(void)
1149{
1150 inet6_del_protocol(&dccp_v6_protocol, IPPROTO_DCCP);
Xin Longa0f9a4c2017-06-20 15:44:44 +08001151 unregister_pernet_subsys(&dccp_v6_ops);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001152 inet6_unregister_protosw(&dccp_v6_protosw);
1153 proto_unregister(&dccp_v6_prot);
1154}
1155
1156module_init(dccp_v6_init);
1157module_exit(dccp_v6_exit);
1158
1159/*
1160 * __stringify doesn't likes enums, so use SOCK_DCCP (6) and IPPROTO_DCCP (33)
1161 * values directly, Also cover the case where the protocol is not specified,
1162 * i.e. net-pf-PF_INET6-proto-0-type-SOCK_DCCP
1163 */
Jean Delvare7131c6c2007-10-21 16:45:03 -07001164MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_INET6, 33, 6);
1165MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_INET6, 0, 6);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001166MODULE_LICENSE("GPL");
1167MODULE_AUTHOR("Arnaldo Carvalho de Melo <acme@mandriva.com>");
1168MODULE_DESCRIPTION("DCCPv6 - Datagram Congestion Controlled Protocol");