blob: ae62c29472785212365aa024b2239240b1cbd8a5 [file] [log] [blame]
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001/*
2 * DCCP over IPv6
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -08003 * Linux INET6 implementation
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08004 *
5 * Based on net/dccp6/ipv6.c
6 *
7 * Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * as published by the Free Software Foundation; either version
12 * 2 of the License, or (at your option) any later version.
13 */
14
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -080015#include <linux/module.h>
16#include <linux/random.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090017#include <linux/slab.h>
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -080018#include <linux/xfrm.h>
19
20#include <net/addrconf.h>
21#include <net/inet_common.h>
22#include <net/inet_hashtables.h>
Arnaldo Carvalho de Melo14c85022005-12-27 02:43:12 -020023#include <net/inet_sock.h>
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -080024#include <net/inet6_connection_sock.h>
25#include <net/inet6_hashtables.h>
26#include <net/ip6_route.h>
27#include <net/ipv6.h>
28#include <net/protocol.h>
29#include <net/transp_v6.h>
David S. Milleraa0e4e42006-01-06 22:55:39 -080030#include <net/ip6_checksum.h>
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -080031#include <net/xfrm.h>
David S. Miller6e5714e2011-08-03 20:50:44 -070032#include <net/secure_seq.h>
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -080033
34#include "dccp.h"
35#include "ipv6.h"
Ian McDonald4b79f0a2006-07-23 23:33:28 -070036#include "feat.h"
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -080037
Pavel Emelyanov13f51d82008-04-14 02:38:45 -070038/* The per-net dccp.v6_ctl_sk is used for sending RSTs and ACKs */
Arnaldo Carvalho de Melo72478872006-03-20 22:00:37 -080039
Stephen Hemminger3b401a82009-09-01 19:25:04 +000040static const struct inet_connection_sock_af_ops dccp_ipv6_mapped;
41static const struct inet_connection_sock_af_ops dccp_ipv6_af_ops;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -080042
Gerrit Renker6f4e5ff2006-11-10 17:43:06 -020043/* add pseudo-header to DCCP checksum stored in skb->csum */
Al Viro868c86b2006-11-14 21:35:48 -080044static inline __sum16 dccp_v6_csum_finish(struct sk_buff *skb,
Eric Dumazetb71d1d42011-04-22 04:53:02 +000045 const struct in6_addr *saddr,
46 const struct in6_addr *daddr)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -080047{
Gerrit Renker6f4e5ff2006-11-10 17:43:06 -020048 return csum_ipv6_magic(saddr, daddr, skb->len, IPPROTO_DCCP, skb->csum);
49}
50
Herbert Xubb296242010-04-11 02:15:55 +000051static inline void dccp_v6_send_check(struct sock *sk, struct sk_buff *skb)
Gerrit Renker6f4e5ff2006-11-10 17:43:06 -020052{
53 struct ipv6_pinfo *np = inet6_sk(sk);
54 struct dccp_hdr *dh = dccp_hdr(skb);
55
56 dccp_csum_outgoing(skb);
Eric Dumazetefe42082013-10-03 15:42:29 -070057 dh->dccph_checksum = dccp_v6_csum_finish(skb, &np->saddr, &sk->sk_v6_daddr);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -080058}
59
David S. Miller6e5714e2011-08-03 20:50:44 -070060static inline __u64 dccp_v6_init_sequence(struct sk_buff *skb)
Gerrit Renkerd7f73652006-11-13 13:34:38 -020061{
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -070062 return secure_dccpv6_sequence_number(ipv6_hdr(skb)->daddr.s6_addr32,
63 ipv6_hdr(skb)->saddr.s6_addr32,
Gerrit Renkerd7f73652006-11-13 13:34:38 -020064 dccp_hdr(skb)->dccph_dport,
65 dccp_hdr(skb)->dccph_sport );
66
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -080067}
68
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -080069static void dccp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
Brian Haleyd5fdd6b2009-06-23 04:31:07 -070070 u8 type, u8 code, int offset, __be32 info)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -080071{
Eric Dumazetb71d1d42011-04-22 04:53:02 +000072 const struct ipv6hdr *hdr = (const struct ipv6hdr *)skb->data;
Eric Dumazet1aa9d1a2016-11-02 20:30:48 -070073 const struct dccp_hdr *dh;
Wei Yongjune0bcfb02008-07-26 11:59:10 +010074 struct dccp_sock *dp;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -080075 struct ipv6_pinfo *np;
76 struct sock *sk;
77 int err;
78 __u64 seq;
Pavel Emelyanovca12a1a2008-07-16 20:28:42 -070079 struct net *net = dev_net(skb->dev);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -080080
Eric Dumazet1aa9d1a2016-11-02 20:30:48 -070081 /* Only need dccph_dport & dccph_sport which are the first
82 * 4 bytes in dccp header.
83 * Our caller (icmpv6_notify()) already pulled 8 bytes for us.
84 */
85 BUILD_BUG_ON(offsetofend(struct dccp_hdr, dccph_sport) > 8);
86 BUILD_BUG_ON(offsetofend(struct dccp_hdr, dccph_dport) > 8);
87 dh = (struct dccp_hdr *)(skb->data + offset);
Wei Yongjun860239c2008-07-26 11:59:11 +010088
Eric Dumazet52036a42015-03-22 10:22:25 -070089 sk = __inet6_lookup_established(net, &dccp_hashinfo,
90 &hdr->daddr, dh->dccph_dport,
91 &hdr->saddr, ntohs(dh->dccph_sport),
92 inet6_iif(skb));
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -080093
Eric Dumazet52036a42015-03-22 10:22:25 -070094 if (!sk) {
Eric Dumazeta16292a2016-04-27 16:44:36 -070095 __ICMP6_INC_STATS(net, __in6_dev_get(skb->dev),
96 ICMP6_MIB_INERRORS);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -080097 return;
98 }
99
100 if (sk->sk_state == DCCP_TIME_WAIT) {
YOSHIFUJI Hideaki9469c7b2006-10-10 19:41:46 -0700101 inet_twsk_put(inet_twsk(sk));
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800102 return;
103 }
Eric Dumazet52036a42015-03-22 10:22:25 -0700104 seq = dccp_hdr_seq(dh);
105 if (sk->sk_state == DCCP_NEW_SYN_RECV)
106 return dccp_req_err(sk, seq);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800107
108 bh_lock_sock(sk);
109 if (sock_owned_by_user(sk))
Eric Dumazet02a1d6e2016-04-27 16:44:39 -0700110 __NET_INC_STATS(net, LINUX_MIB_LOCKDROPPEDICMPS);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800111
112 if (sk->sk_state == DCCP_CLOSED)
113 goto out;
114
Wei Yongjune0bcfb02008-07-26 11:59:10 +0100115 dp = dccp_sk(sk);
Wei Yongjune0bcfb02008-07-26 11:59:10 +0100116 if ((1 << sk->sk_state) & ~(DCCPF_REQUESTING | DCCPF_LISTEN) &&
117 !between48(seq, dp->dccps_awl, dp->dccps_awh)) {
Eric Dumazet02a1d6e2016-04-27 16:44:39 -0700118 __NET_INC_STATS(net, LINUX_MIB_OUTOFWINDOWICMPS);
Wei Yongjune0bcfb02008-07-26 11:59:10 +0100119 goto out;
120 }
121
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800122 np = inet6_sk(sk);
123
David S. Millerec18d9a2012-07-12 00:25:15 -0700124 if (type == NDISC_REDIRECT) {
Jon Maxwell98933eb2017-03-10 16:40:33 +1100125 if (!sock_owned_by_user(sk)) {
126 struct dst_entry *dst = __sk_dst_check(sk, np->dst_cookie);
David S. Millerec18d9a2012-07-12 00:25:15 -0700127
Jon Maxwell98933eb2017-03-10 16:40:33 +1100128 if (dst)
129 dst->ops->redirect(dst, sk, skb);
130 }
Duan Jiongbd784a12013-09-18 20:03:27 +0800131 goto out;
David S. Millerec18d9a2012-07-12 00:25:15 -0700132 }
133
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800134 if (type == ICMPV6_PKT_TOOBIG) {
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800135 struct dst_entry *dst = NULL;
136
Hannes Frederic Sowa93b36cf2013-12-15 03:41:14 +0100137 if (!ip6_sk_accept_pmtu(sk))
138 goto out;
139
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800140 if (sock_owned_by_user(sk))
141 goto out;
142 if ((1 << sk->sk_state) & (DCCPF_LISTEN | DCCPF_CLOSED))
143 goto out;
144
David S. Miller35ad9b92012-07-16 03:44:56 -0700145 dst = inet6_csk_update_pmtu(sk, ntohl(info));
146 if (!dst)
147 goto out;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800148
David S. Miller35ad9b92012-07-16 03:44:56 -0700149 if (inet_csk(sk)->icsk_pmtu_cookie > dst_mtu(dst))
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800150 dccp_sync_mss(sk, dst_mtu(dst));
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800151 goto out;
152 }
153
154 icmpv6_err_convert(type, code, &err);
155
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800156 /* Might be for an request_sock */
157 switch (sk->sk_state) {
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800158 case DCCP_REQUESTING:
159 case DCCP_RESPOND: /* Cannot happen.
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800160 It can, it SYNs are crossed. --ANK */
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800161 if (!sock_owned_by_user(sk)) {
Eric Dumazetaa62d762016-04-27 16:44:28 -0700162 __DCCP_INC_STATS(DCCP_MIB_ATTEMPTFAILS);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800163 sk->sk_err = err;
164 /*
165 * Wake people up to see the error
166 * (see connect in sock.c)
167 */
168 sk->sk_error_report(sk);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800169 dccp_done(sk);
170 } else
171 sk->sk_err_soft = err;
172 goto out;
173 }
174
175 if (!sock_owned_by_user(sk) && np->recverr) {
176 sk->sk_err = err;
177 sk->sk_error_report(sk);
178 } else
179 sk->sk_err_soft = err;
180
181out:
182 bh_unlock_sock(sk);
183 sock_put(sk);
184}
185
186
Eric Dumazetea3bea32015-09-25 07:39:23 -0700187static int dccp_v6_send_response(const struct sock *sk, struct request_sock *req)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800188{
Eric Dumazet634fb9792013-10-09 15:21:29 -0700189 struct inet_request_sock *ireq = inet_rsk(req);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800190 struct ipv6_pinfo *np = inet6_sk(sk);
191 struct sk_buff *skb;
Arnaud Ebalard20c59de2010-06-01 21:35:01 +0000192 struct in6_addr *final_p, final;
David S. Miller4c9483b2011-03-12 16:22:43 -0500193 struct flowi6 fl6;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800194 int err = -1;
Denis V. Lunevfd80eb92008-02-29 11:43:03 -0800195 struct dst_entry *dst;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800196
David S. Miller4c9483b2011-03-12 16:22:43 -0500197 memset(&fl6, 0, sizeof(fl6));
198 fl6.flowi6_proto = IPPROTO_DCCP;
Eric Dumazet634fb9792013-10-09 15:21:29 -0700199 fl6.daddr = ireq->ir_v6_rmt_addr;
200 fl6.saddr = ireq->ir_v6_loc_addr;
David S. Miller4c9483b2011-03-12 16:22:43 -0500201 fl6.flowlabel = 0;
Eric Dumazet634fb9792013-10-09 15:21:29 -0700202 fl6.flowi6_oif = ireq->ir_iif;
203 fl6.fl6_dport = ireq->ir_rmt_port;
Eric Dumazetb44084c2013-10-10 00:04:37 -0700204 fl6.fl6_sport = htons(ireq->ir_num);
David S. Miller4c9483b2011-03-12 16:22:43 -0500205 security_req_classify_flow(req, flowi6_to_flowi(&fl6));
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800206
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800207
Eric Dumazet45f6fad2015-11-29 19:37:57 -0800208 rcu_read_lock();
209 final_p = fl6_update_dst(&fl6, rcu_dereference(np->opt), &final);
210 rcu_read_unlock();
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800211
Sabrina Dubroca5cc5fa72019-12-04 15:35:52 +0100212 dst = ip6_dst_lookup_flow(sock_net(sk), sk, &fl6, final_p);
David S. Miller68d0c6d2011-03-01 13:19:07 -0800213 if (IS_ERR(dst)) {
214 err = PTR_ERR(dst);
215 dst = NULL;
Denis V. Lunevfd80eb92008-02-29 11:43:03 -0800216 goto done;
David S. Miller68d0c6d2011-03-01 13:19:07 -0800217 }
Denis V. Lunevfd80eb92008-02-29 11:43:03 -0800218
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800219 skb = dccp_make_response(sk, dst, req);
220 if (skb != NULL) {
221 struct dccp_hdr *dh = dccp_hdr(skb);
Huw Davies56ac42b2016-06-27 15:05:28 -0400222 struct ipv6_txoptions *opt;
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800223
Gerrit Renker6f4e5ff2006-11-10 17:43:06 -0200224 dh->dccph_checksum = dccp_v6_csum_finish(skb,
Eric Dumazet634fb9792013-10-09 15:21:29 -0700225 &ireq->ir_v6_loc_addr,
226 &ireq->ir_v6_rmt_addr);
227 fl6.daddr = ireq->ir_v6_rmt_addr;
Eric Dumazet45f6fad2015-11-29 19:37:57 -0800228 rcu_read_lock();
Huw Davies56ac42b2016-06-27 15:05:28 -0400229 opt = ireq->ipv6_opt;
230 if (!opt)
231 opt = rcu_dereference(np->opt);
Pablo Neira0d4c19e2017-01-26 22:56:21 +0100232 err = ip6_xmit(sk, skb, &fl6, sk->sk_mark, opt, np->tclass);
Eric Dumazet45f6fad2015-11-29 19:37:57 -0800233 rcu_read_unlock();
Gerrit Renkerb9df3cb2006-11-14 11:21:36 -0200234 err = net_xmit_eval(err);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800235 }
236
237done:
David S. Miller0cbd7822006-01-31 17:53:37 -0800238 dst_release(dst);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800239 return err;
240}
241
242static void dccp_v6_reqsk_destructor(struct request_sock *req)
243{
Gerrit Renkerd99a7bd2008-11-04 23:56:30 -0800244 dccp_feat_list_purge(&dccp_rsk(req)->dreq_featneg);
Huw Davies56ac42b2016-06-27 15:05:28 -0400245 kfree(inet_rsk(req)->ipv6_opt);
Eric Dumazet634fb9792013-10-09 15:21:29 -0700246 kfree_skb(inet_rsk(req)->pktopts);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800247}
248
Eric Dumazeta00e7442015-09-29 07:42:39 -0700249static void dccp_v6_ctl_send_reset(const struct sock *sk, struct sk_buff *rxskb)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800250{
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000251 const struct ipv6hdr *rxip6h;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800252 struct sk_buff *skb;
David S. Miller4c9483b2011-03-12 16:22:43 -0500253 struct flowi6 fl6;
Eric Dumazetadf30902009-06-02 05:19:30 +0000254 struct net *net = dev_net(skb_dst(rxskb)->dev);
Pavel Emelyanov334527d2008-04-13 22:32:45 -0700255 struct sock *ctl_sk = net->dccp.v6_ctl_sk;
Eric Dumazetadf30902009-06-02 05:19:30 +0000256 struct dst_entry *dst;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800257
Gerrit Renkere356d372007-09-26 14:35:19 -0300258 if (dccp_hdr(rxskb)->dccph_type == DCCP_PKT_RESET)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800259 return;
260
261 if (!ipv6_unicast_destination(rxskb))
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800262 return;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800263
Pavel Emelyanov02047742008-04-13 22:32:25 -0700264 skb = dccp_ctl_make_reset(ctl_sk, rxskb);
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800265 if (skb == NULL)
Arnaldo Carvalho de Melo8109b022006-12-10 16:01:18 -0200266 return;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800267
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700268 rxip6h = ipv6_hdr(rxskb);
Gerrit Renkere356d372007-09-26 14:35:19 -0300269 dccp_hdr(skb)->dccph_checksum = dccp_v6_csum_finish(skb, &rxip6h->saddr,
270 &rxip6h->daddr);
Gerrit Renker6f4e5ff2006-11-10 17:43:06 -0200271
David S. Miller4c9483b2011-03-12 16:22:43 -0500272 memset(&fl6, 0, sizeof(fl6));
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +0000273 fl6.daddr = rxip6h->saddr;
274 fl6.saddr = rxip6h->daddr;
Gerrit Renker6f4e5ff2006-11-10 17:43:06 -0200275
David S. Miller4c9483b2011-03-12 16:22:43 -0500276 fl6.flowi6_proto = IPPROTO_DCCP;
277 fl6.flowi6_oif = inet6_iif(rxskb);
David S. Miller1958b852011-03-12 16:36:19 -0500278 fl6.fl6_dport = dccp_hdr(skb)->dccph_dport;
279 fl6.fl6_sport = dccp_hdr(skb)->dccph_sport;
David S. Miller4c9483b2011-03-12 16:22:43 -0500280 security_skb_classify_flow(rxskb, flowi6_to_flowi(&fl6));
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800281
282 /* sk = NULL, but it is safe for now. RST socket required. */
Sabrina Dubroca5cc5fa72019-12-04 15:35:52 +0100283 dst = ip6_dst_lookup_flow(sock_net(ctl_sk), ctl_sk, &fl6, NULL);
David S. Miller68d0c6d2011-03-01 13:19:07 -0800284 if (!IS_ERR(dst)) {
285 skb_dst_set(skb, dst);
Pablo Neira0d4c19e2017-01-26 22:56:21 +0100286 ip6_xmit(ctl_sk, skb, &fl6, 0, NULL, 0);
Eric Dumazet7309f882016-04-29 14:16:49 -0700287 DCCP_INC_STATS(DCCP_MIB_OUTSEGS);
288 DCCP_INC_STATS(DCCP_MIB_OUTRSTS);
David S. Miller68d0c6d2011-03-01 13:19:07 -0800289 return;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800290 }
291
292 kfree_skb(skb);
293}
294
Gerrit Renker73c9e022006-11-10 13:01:31 -0200295static struct request_sock_ops dccp6_request_sock_ops = {
296 .family = AF_INET6,
297 .obj_size = sizeof(struct dccp6_request_sock),
298 .rtx_syn_ack = dccp_v6_send_response,
299 .send_ack = dccp_reqsk_send_ack,
300 .destructor = dccp_v6_reqsk_destructor,
301 .send_reset = dccp_v6_ctl_send_reset,
Eric Dumazetc72e1182012-04-12 22:16:05 +0000302 .syn_ack_timeout = dccp_syn_ack_timeout,
Gerrit Renker73c9e022006-11-10 13:01:31 -0200303};
304
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800305static int dccp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
306{
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800307 struct request_sock *req;
308 struct dccp_request_sock *dreq;
Eric Dumazet634fb9792013-10-09 15:21:29 -0700309 struct inet_request_sock *ireq;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800310 struct ipv6_pinfo *np = inet6_sk(sk);
Arnaldo Carvalho de Melo8109b022006-12-10 16:01:18 -0200311 const __be32 service = dccp_hdr_request(skb)->dccph_req_service;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800312 struct dccp_skb_cb *dcb = DCCP_SKB_CB(skb);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800313
314 if (skb->protocol == htons(ETH_P_IP))
315 return dccp_v4_conn_request(sk, skb);
316
317 if (!ipv6_unicast_destination(skb))
Gerrit Renker4a5409a2007-10-04 14:52:28 -0700318 return 0; /* discard, don't send a reset here */
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800319
Jakub Kicinski1c503dd2021-03-17 09:55:15 -0700320 if (ipv6_addr_v4mapped(&ipv6_hdr(skb)->saddr)) {
321 __IP6_INC_STATS(sock_net(sk), NULL, IPSTATS_MIB_INHDRERRORS);
322 return 0;
323 }
324
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800325 if (dccp_bad_service_code(sk, service)) {
Gerrit Renker4a5409a2007-10-04 14:52:28 -0700326 dcb->dccpd_reset_code = DCCP_RESET_CODE_BAD_SERVICE_CODE;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800327 goto drop;
Arnaldo Carvalho de Melo8109b022006-12-10 16:01:18 -0200328 }
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800329 /*
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800330 * There are no SYN attacks on IPv6, yet...
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800331 */
Gerrit Renker4a5409a2007-10-04 14:52:28 -0700332 dcb->dccpd_reset_code = DCCP_RESET_CODE_TOO_BUSY;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800333 if (inet_csk_reqsk_queue_is_full(sk))
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800334 goto drop;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800335
Eric Dumazetdfe4f692016-10-26 09:27:57 -0700336 if (sk_acceptq_is_full(sk))
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800337 goto drop;
338
Eric Dumazeta1a53442015-10-04 21:08:11 -0700339 req = inet_reqsk_alloc(&dccp6_request_sock_ops, sk, true);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800340 if (req == NULL)
341 goto drop;
342
Gerrit Renkerac757732008-11-04 23:55:49 -0800343 if (dccp_reqsk_init(req, dccp_sk(sk), skb))
344 goto drop_and_free;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800345
Gerrit Renker8b819412007-12-13 12:29:24 -0200346 dreq = dccp_rsk(req);
347 if (dccp_parse_options(sk, dreq, skb))
348 goto drop_and_free;
349
Venkat Yekkirala4237c752006-07-24 23:32:50 -0700350 if (security_inet_conn_request(sk, skb, req))
351 goto drop_and_free;
352
Eric Dumazet634fb9792013-10-09 15:21:29 -0700353 ireq = inet_rsk(req);
354 ireq->ir_v6_rmt_addr = ipv6_hdr(skb)->saddr;
355 ireq->ir_v6_loc_addr = ipv6_hdr(skb)->daddr;
Eric Dumazet3f66b082015-03-12 16:44:10 -0700356 ireq->ireq_family = AF_INET6;
Eric Dumazet543cb052018-04-07 13:42:41 -0700357 ireq->ir_mark = inet_request_mark(sk, skb);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800358
Eric Dumazeta2247722014-09-27 09:50:56 -0700359 if (ipv6_opt_accepted(sk, skb, IP6CB(skb)) ||
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800360 np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo ||
361 np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim) {
362 atomic_inc(&skb->users);
Eric Dumazet634fb9792013-10-09 15:21:29 -0700363 ireq->pktopts = skb;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800364 }
Eric Dumazet634fb9792013-10-09 15:21:29 -0700365 ireq->ir_iif = sk->sk_bound_dev_if;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800366
367 /* So that link locals have meaning */
368 if (!sk->sk_bound_dev_if &&
Eric Dumazet634fb9792013-10-09 15:21:29 -0700369 ipv6_addr_type(&ireq->ir_v6_rmt_addr) & IPV6_ADDR_LINKLOCAL)
370 ireq->ir_iif = inet6_iif(skb);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800371
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800372 /*
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800373 * Step 3: Process LISTEN state
374 *
Gerrit Renkerd83ca5a2006-11-10 16:29:14 -0200375 * Set S.ISR, S.GSR, S.SWL, S.SWH from packet or Init Cookie
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800376 *
Samuel Jerof541fb72012-02-26 18:22:02 -0700377 * Setting S.SWL/S.SWH to is deferred to dccp_create_openreq_child().
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800378 */
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800379 dreq->dreq_isr = dcb->dccpd_seq;
Samuel Jerof541fb72012-02-26 18:22:02 -0700380 dreq->dreq_gsr = dreq->dreq_isr;
Gerrit Renker865e9022006-11-13 13:31:50 -0200381 dreq->dreq_iss = dccp_v6_init_sequence(skb);
Samuel Jerof541fb72012-02-26 18:22:02 -0700382 dreq->dreq_gss = dreq->dreq_iss;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800383 dreq->dreq_service = service;
384
Christoph Paasch1a2c6182013-03-17 08:23:34 +0000385 if (dccp_v6_send_response(sk, req))
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800386 goto drop_and_free;
387
Eric Dumazet079096f2015-10-02 11:43:32 -0700388 inet_csk_reqsk_queue_hash_add(sk, req, DCCP_TIMEOUT_INIT);
Xin Long9ffa6722017-07-26 14:19:09 +0800389 reqsk_put(req);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800390 return 0;
391
392drop_and_free:
393 reqsk_free(req);
394drop:
Eric Dumazetaa62d762016-04-27 16:44:28 -0700395 __DCCP_INC_STATS(DCCP_MIB_ATTEMPTFAILS);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800396 return -1;
397}
398
Eric Dumazet0c271712015-09-29 07:42:48 -0700399static struct sock *dccp_v6_request_recv_sock(const struct sock *sk,
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800400 struct sk_buff *skb,
401 struct request_sock *req,
Eric Dumazet5e0724d2015-10-22 08:20:46 -0700402 struct dst_entry *dst,
403 struct request_sock *req_unhash,
404 bool *own_req)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800405{
Eric Dumazet634fb9792013-10-09 15:21:29 -0700406 struct inet_request_sock *ireq = inet_rsk(req);
Eric Dumazet0c271712015-09-29 07:42:48 -0700407 struct ipv6_pinfo *newnp;
408 const struct ipv6_pinfo *np = inet6_sk(sk);
Eric Dumazet45f6fad2015-11-29 19:37:57 -0800409 struct ipv6_txoptions *opt;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800410 struct inet_sock *newinet;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800411 struct dccp6_sock *newdp6;
412 struct sock *newsk;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800413
414 if (skb->protocol == htons(ETH_P_IP)) {
415 /*
416 * v6 mapped
417 */
Eric Dumazet5e0724d2015-10-22 08:20:46 -0700418 newsk = dccp_v4_request_recv_sock(sk, skb, req, dst,
419 req_unhash, own_req);
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800420 if (newsk == NULL)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800421 return NULL;
422
423 newdp6 = (struct dccp6_sock *)newsk;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800424 newinet = inet_sk(newsk);
425 newinet->pinet6 = &newdp6->inet6;
426 newnp = inet6_sk(newsk);
427
428 memcpy(newnp, np, sizeof(struct ipv6_pinfo));
429
Eric Dumazetd1e559d2015-03-18 14:05:35 -0700430 newnp->saddr = newsk->sk_v6_rcv_saddr;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800431
432 inet_csk(newsk)->icsk_af_ops = &dccp_ipv6_mapped;
433 newsk->sk_backlog_rcv = dccp_v4_do_rcv;
434 newnp->pktoptions = NULL;
435 newnp->opt = NULL;
WANG Cong4bd8f5e2017-05-09 16:59:54 -0700436 newnp->ipv6_mc_list = NULL;
437 newnp->ipv6_ac_list = NULL;
438 newnp->ipv6_fl_list = NULL;
Eric Dumazetdc8390f2019-03-19 05:46:18 -0700439 newnp->mcast_oif = inet_iif(skb);
440 newnp->mcast_hops = ip_hdr(skb)->ttl;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800441
442 /*
443 * No need to charge this sock to the relevant IPv6 refcnt debug socks count
444 * here, dccp_create_openreq_child now does this for us, see the comment in
445 * that function for the gory details. -acme
446 */
447
448 /* It is tricky place. Until this moment IPv4 tcp
449 worked with IPv6 icsk.icsk_af_ops.
450 Sync it now.
451 */
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -0800452 dccp_sync_mss(newsk, inet_csk(newsk)->icsk_pmtu_cookie);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800453
454 return newsk;
455 }
456
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800457
458 if (sk_acceptq_is_full(sk))
459 goto out_overflow;
460
Eric Dumazetf76b33c2015-09-29 07:42:42 -0700461 if (!dst) {
David S. Miller4c9483b2011-03-12 16:22:43 -0500462 struct flowi6 fl6;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800463
Eric Dumazetf76b33c2015-09-29 07:42:42 -0700464 dst = inet6_csk_route_req(sk, &fl6, req, IPPROTO_DCCP);
465 if (!dst)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800466 goto out;
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800467 }
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800468
469 newsk = dccp_create_openreq_child(sk, req, skb);
470 if (newsk == NULL)
Balazs Scheidler093d2822010-10-21 13:06:43 +0200471 goto out_nonewsk;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800472
473 /*
474 * No need to charge this sock to the relevant IPv6 refcnt debug socks
475 * count here, dccp_create_openreq_child now does this for us, see the
476 * comment in that function for the gory details. -acme
477 */
478
Eric Dumazet6bd4f352015-12-02 21:53:57 -0800479 ip6_dst_store(newsk, dst, NULL, NULL);
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800480 newsk->sk_route_caps = dst->dev->features & ~(NETIF_F_IP_CSUM |
481 NETIF_F_TSO);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800482 newdp6 = (struct dccp6_sock *)newsk;
483 newinet = inet_sk(newsk);
484 newinet->pinet6 = &newdp6->inet6;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800485 newnp = inet6_sk(newsk);
486
487 memcpy(newnp, np, sizeof(struct ipv6_pinfo));
488
Eric Dumazet634fb9792013-10-09 15:21:29 -0700489 newsk->sk_v6_daddr = ireq->ir_v6_rmt_addr;
490 newnp->saddr = ireq->ir_v6_loc_addr;
491 newsk->sk_v6_rcv_saddr = ireq->ir_v6_loc_addr;
492 newsk->sk_bound_dev_if = ireq->ir_iif;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800493
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800494 /* Now IPv6 options...
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800495
496 First: no IPv4 options.
497 */
Eric Dumazetf6d8bd02011-04-21 09:45:37 +0000498 newinet->inet_opt = NULL;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800499
500 /* Clone RX bits */
501 newnp->rxopt.all = np->rxopt.all;
502
WANG Cong4bd8f5e2017-05-09 16:59:54 -0700503 newnp->ipv6_mc_list = NULL;
504 newnp->ipv6_ac_list = NULL;
505 newnp->ipv6_fl_list = NULL;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800506 newnp->pktoptions = NULL;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800507 newnp->opt = NULL;
508 newnp->mcast_oif = inet6_iif(skb);
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700509 newnp->mcast_hops = ipv6_hdr(skb)->hop_limit;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800510
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800511 /*
512 * Clone native IPv6 options from listening socket (if any)
513 *
514 * Yes, keeping reference count would be much more clever, but we make
515 * one more one thing there: reattach optmem to newsk.
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800516 */
Huw Davies56ac42b2016-06-27 15:05:28 -0400517 opt = ireq->ipv6_opt;
518 if (!opt)
519 opt = rcu_dereference(np->opt);
Eric Dumazet45f6fad2015-11-29 19:37:57 -0800520 if (opt) {
521 opt = ipv6_dup_options(newsk, opt);
522 RCU_INIT_POINTER(newnp->opt, opt);
523 }
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -0800524 inet_csk(newsk)->icsk_ext_hdr_len = 0;
Eric Dumazet45f6fad2015-11-29 19:37:57 -0800525 if (opt)
526 inet_csk(newsk)->icsk_ext_hdr_len = opt->opt_nflen +
527 opt->opt_flen;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800528
529 dccp_sync_mss(newsk, dst_mtu(dst));
530
Eric Dumazetc720c7e2009-10-15 06:30:45 +0000531 newinet->inet_daddr = newinet->inet_saddr = LOOPBACK4_IPV6;
532 newinet->inet_rcv_saddr = LOOPBACK4_IPV6;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800533
Balazs Scheidler093d2822010-10-21 13:06:43 +0200534 if (__inet_inherit_port(sk, newsk) < 0) {
Christoph Paasche337e242012-12-14 04:07:58 +0000535 inet_csk_prepare_forced_close(newsk);
536 dccp_done(newsk);
Balazs Scheidler093d2822010-10-21 13:06:43 +0200537 goto out;
538 }
Eric Dumazet5e0724d2015-10-22 08:20:46 -0700539 *own_req = inet_ehash_nolisten(newsk, req_to_sk(req_unhash));
Eric Dumazetce105002015-10-30 09:46:12 -0700540 /* Clone pktoptions received with SYN, if we own the req */
541 if (*own_req && ireq->pktopts) {
542 newnp->pktoptions = skb_clone(ireq->pktopts, GFP_ATOMIC);
543 consume_skb(ireq->pktopts);
544 ireq->pktopts = NULL;
545 if (newnp->pktoptions)
546 skb_set_owner_r(newnp->pktoptions, newsk);
547 }
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800548
549 return newsk;
550
551out_overflow:
Eric Dumazet02a1d6e2016-04-27 16:44:39 -0700552 __NET_INC_STATS(sock_net(sk), LINUX_MIB_LISTENOVERFLOWS);
Balazs Scheidler093d2822010-10-21 13:06:43 +0200553out_nonewsk:
554 dst_release(dst);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800555out:
Eric Dumazet02a1d6e2016-04-27 16:44:39 -0700556 __NET_INC_STATS(sock_net(sk), LINUX_MIB_LISTENDROPS);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800557 return NULL;
558}
559
560/* The socket must have it's spinlock held when we get
561 * here.
562 *
563 * We have a potential double-lock case here, so even when
564 * doing backlog processing we use the BH locking scheme.
565 * This is because we cannot sleep with the original spinlock
566 * held.
567 */
568static int dccp_v6_do_rcv(struct sock *sk, struct sk_buff *skb)
569{
570 struct ipv6_pinfo *np = inet6_sk(sk);
571 struct sk_buff *opt_skb = NULL;
572
573 /* Imagine: socket is IPv6. IPv4 packet arrives,
574 goes to IPv4 receive handler and backlogged.
575 From backlog it always goes here. Kerboom...
576 Fortunately, dccp_rcv_established and rcv_established
577 handle them correctly, but it is not case with
578 dccp_v6_hnd_req and dccp_v6_ctl_send_reset(). --ANK
579 */
580
581 if (skb->protocol == htons(ETH_P_IP))
582 return dccp_v4_do_rcv(sk, skb);
583
Dmitry Mishinfda9ef52006-08-31 15:28:39 -0700584 if (sk_filter(sk, skb))
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800585 goto discard;
586
587 /*
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800588 * socket locking is here for SMP purposes as backlog rcv is currently
589 * called with bh processing disabled.
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800590 */
591
592 /* Do Stevens' IPV6_PKTOPTIONS.
593
594 Yes, guys, it is the only place in our code, where we
595 may make it not affecting IPv4.
596 The rest of code is protocol independent,
597 and I do not like idea to uglify IPv4.
598
599 Actually, all the idea behind IPV6_PKTOPTIONS
600 looks not very well thought. For now we latch
601 options, received in the last packet, enqueued
602 by tcp. Feel free to propose better solution.
YOSHIFUJI Hideakic9eaf172007-02-09 23:24:38 +0900603 --ANK (980728)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800604 */
605 if (np->rxopt.all)
Gerrit Renker89e7e572006-11-10 11:13:33 -0200606 /*
607 * FIXME: Add handling of IPV6_PKTOPTIONS skb. See the comments below
608 * (wrt ipv6_pktopions) and net/ipv6/tcp_ipv6.c for an example.
609 */
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800610 opt_skb = skb_clone(skb, GFP_ATOMIC);
611
612 if (sk->sk_state == DCCP_OPEN) { /* Fast path */
613 if (dccp_rcv_established(sk, skb, dccp_hdr(skb), skb->len))
614 goto reset;
David S. Millerfd169f12006-10-20 19:44:17 -0700615 if (opt_skb) {
Gerrit Renker89e7e572006-11-10 11:13:33 -0200616 /* XXX This is where we would goto ipv6_pktoptions. */
David S. Millerfd169f12006-10-20 19:44:17 -0700617 __kfree_skb(opt_skb);
618 }
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800619 return 0;
620 }
621
Gerrit Renkerd83ca5a2006-11-10 16:29:14 -0200622 /*
623 * Step 3: Process LISTEN state
624 * If S.state == LISTEN,
625 * If P.type == Request or P contains a valid Init Cookie option,
626 * (* Must scan the packet's options to check for Init
627 * Cookies. Only Init Cookies are processed here,
628 * however; other options are processed in Step 8. This
629 * scan need only be performed if the endpoint uses Init
630 * Cookies *)
631 * (* Generate a new socket and switch to that socket *)
632 * Set S := new socket for this port pair
633 * S.state = RESPOND
634 * Choose S.ISS (initial seqno) or set from Init Cookies
635 * Initialize S.GAR := S.ISS
636 * Set S.ISR, S.GSR, S.SWL, S.SWH from packet or Init Cookies
637 * Continue with S.state == RESPOND
638 * (* A Response packet will be generated in Step 11 *)
639 * Otherwise,
640 * Generate Reset(No Connection) unless P.type == Reset
641 * Drop packet and return
642 *
643 * NOTE: the check for the packet types is done in
644 * dccp_rcv_state_process
645 */
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800646
647 if (dccp_rcv_state_process(sk, skb, dccp_hdr(skb), skb->len))
648 goto reset;
David S. Millerfd169f12006-10-20 19:44:17 -0700649 if (opt_skb) {
Gerrit Renker89e7e572006-11-10 11:13:33 -0200650 /* XXX This is where we would goto ipv6_pktoptions. */
David S. Millerfd169f12006-10-20 19:44:17 -0700651 __kfree_skb(opt_skb);
652 }
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800653 return 0;
654
655reset:
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800656 dccp_v6_ctl_send_reset(sk, skb);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800657discard:
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800658 if (opt_skb != NULL)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800659 __kfree_skb(opt_skb);
660 kfree_skb(skb);
661 return 0;
662}
663
Herbert Xue5bbef22007-10-15 12:50:28 -0700664static int dccp_v6_rcv(struct sk_buff *skb)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800665{
666 const struct dccp_hdr *dh;
Eric Dumazet3b24d852016-04-01 08:52:17 -0700667 bool refcounted;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800668 struct sock *sk;
Gerrit Renker6f4e5ff2006-11-10 17:43:06 -0200669 int min_cov;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800670
Gerrit Renker6f4e5ff2006-11-10 17:43:06 -0200671 /* Step 1: Check header basics */
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800672
673 if (dccp_invalid_packet(skb))
674 goto discard_it;
675
Gerrit Renker6f4e5ff2006-11-10 17:43:06 -0200676 /* Step 1: If header checksum is incorrect, drop packet and return. */
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700677 if (dccp_v6_csum_finish(skb, &ipv6_hdr(skb)->saddr,
678 &ipv6_hdr(skb)->daddr)) {
Gerrit Renker59348b12006-11-20 18:39:23 -0200679 DCCP_WARN("dropped packet with invalid checksum\n");
Gerrit Renker6f4e5ff2006-11-10 17:43:06 -0200680 goto discard_it;
681 }
682
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800683 dh = dccp_hdr(skb);
684
Gerrit Renkerfde20102007-10-24 10:12:09 -0200685 DCCP_SKB_CB(skb)->dccpd_seq = dccp_hdr_seq(dh);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800686 DCCP_SKB_CB(skb)->dccpd_type = dh->dccph_type;
687
688 if (dccp_packet_without_ack(skb))
689 DCCP_SKB_CB(skb)->dccpd_ack_seq = DCCP_PKT_WITHOUT_ACK_SEQ;
690 else
691 DCCP_SKB_CB(skb)->dccpd_ack_seq = dccp_hdr_ack_seq(skb);
692
Eric Dumazet4bdc3d62015-10-13 17:12:54 -0700693lookup:
Craig Galleka5836362016-02-10 11:50:38 -0500694 sk = __inet6_lookup_skb(&dccp_hashinfo, skb, __dccp_hdr_len(dh),
Eric Dumazet870c3152014-10-17 09:17:20 -0700695 dh->dccph_sport, dh->dccph_dport,
Eric Dumazet3b24d852016-04-01 08:52:17 -0700696 inet6_iif(skb), &refcounted);
Eric Dumazet4bdc3d62015-10-13 17:12:54 -0700697 if (!sk) {
Gerrit Renkerd23c7102006-11-10 11:46:34 -0200698 dccp_pr_debug("failed to look up flow ID in table and "
699 "get corresponding socket\n");
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800700 goto no_dccp_socket;
Gerrit Renkerd23c7102006-11-10 11:46:34 -0200701 }
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800702
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800703 /*
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800704 * Step 2:
Arnaldo Carvalho de Melo8109b022006-12-10 16:01:18 -0200705 * ... or S.state == TIMEWAIT,
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800706 * Generate Reset(No Connection) unless P.type == Reset
707 * Drop packet and return
708 */
Gerrit Renkerd23c7102006-11-10 11:46:34 -0200709 if (sk->sk_state == DCCP_TIME_WAIT) {
710 dccp_pr_debug("sk->sk_state == DCCP_TIME_WAIT: do_time_wait\n");
711 inet_twsk_put(inet_twsk(sk));
712 goto no_dccp_socket;
713 }
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800714
Eric Dumazet079096f2015-10-02 11:43:32 -0700715 if (sk->sk_state == DCCP_NEW_SYN_RECV) {
716 struct request_sock *req = inet_reqsk(sk);
Eric Dumazet77166822016-02-18 05:39:18 -0800717 struct sock *nsk;
Eric Dumazet079096f2015-10-02 11:43:32 -0700718
719 sk = req->rsk_listener;
Eric Dumazet77166822016-02-18 05:39:18 -0800720 if (unlikely(sk->sk_state != DCCP_LISTEN)) {
Eric Dumazetf03f2e12015-10-14 11:16:27 -0700721 inet_csk_reqsk_queue_drop_and_put(sk, req);
Eric Dumazet4bdc3d62015-10-13 17:12:54 -0700722 goto lookup;
723 }
Eric Dumazet77166822016-02-18 05:39:18 -0800724 sock_hold(sk);
Eric Dumazet3b24d852016-04-01 08:52:17 -0700725 refcounted = true;
Eric Dumazet77166822016-02-18 05:39:18 -0800726 nsk = dccp_check_req(sk, skb, req);
Eric Dumazet079096f2015-10-02 11:43:32 -0700727 if (!nsk) {
728 reqsk_put(req);
Eric Dumazet77166822016-02-18 05:39:18 -0800729 goto discard_and_relse;
Eric Dumazet079096f2015-10-02 11:43:32 -0700730 }
731 if (nsk == sk) {
Eric Dumazet079096f2015-10-02 11:43:32 -0700732 reqsk_put(req);
733 } else if (dccp_child_process(sk, nsk, skb)) {
734 dccp_v6_ctl_send_reset(sk, skb);
Eric Dumazet77166822016-02-18 05:39:18 -0800735 goto discard_and_relse;
Eric Dumazet079096f2015-10-02 11:43:32 -0700736 } else {
Eric Dumazet77166822016-02-18 05:39:18 -0800737 sock_put(sk);
Eric Dumazet079096f2015-10-02 11:43:32 -0700738 return 0;
739 }
740 }
Gerrit Renker6f4e5ff2006-11-10 17:43:06 -0200741 /*
742 * RFC 4340, sec. 9.2.1: Minimum Checksum Coverage
Arnaldo Carvalho de Melo8109b022006-12-10 16:01:18 -0200743 * o if MinCsCov = 0, only packets with CsCov = 0 are accepted
744 * o if MinCsCov > 0, also accept packets with CsCov >= MinCsCov
Gerrit Renker6f4e5ff2006-11-10 17:43:06 -0200745 */
746 min_cov = dccp_sk(sk)->dccps_pcrlen;
747 if (dh->dccph_cscov && (min_cov == 0 || dh->dccph_cscov < min_cov)) {
748 dccp_pr_debug("Packet CsCov %d does not satisfy MinCsCov %d\n",
749 dh->dccph_cscov, min_cov);
750 /* FIXME: send Data Dropped option (see also dccp_v4_rcv) */
751 goto discard_and_relse;
752 }
753
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800754 if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb))
755 goto discard_and_relse;
756
Eric Dumazetc3f24cf2016-11-02 17:14:41 -0700757 return __sk_receive_skb(sk, skb, 1, dh->dccph_doff * 4,
758 refcounted) ? -1 : 0;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800759
760no_dccp_socket:
761 if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb))
762 goto discard_it;
763 /*
764 * Step 2:
Arnaldo Carvalho de Melo8109b022006-12-10 16:01:18 -0200765 * If no socket ...
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800766 * Generate Reset(No Connection) unless P.type == Reset
767 * Drop packet and return
768 */
769 if (dh->dccph_type != DCCP_PKT_RESET) {
770 DCCP_SKB_CB(skb)->dccpd_reset_code =
771 DCCP_RESET_CODE_NO_CONNECTION;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800772 dccp_v6_ctl_send_reset(sk, skb);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800773 }
Gerrit Renkerd23c7102006-11-10 11:46:34 -0200774
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800775discard_it:
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800776 kfree_skb(skb);
777 return 0;
778
779discard_and_relse:
Eric Dumazet3b24d852016-04-01 08:52:17 -0700780 if (refcounted)
781 sock_put(sk);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800782 goto discard_it;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800783}
784
Gerrit Renker73c9e022006-11-10 13:01:31 -0200785static int dccp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
786 int addr_len)
787{
788 struct sockaddr_in6 *usin = (struct sockaddr_in6 *)uaddr;
789 struct inet_connection_sock *icsk = inet_csk(sk);
790 struct inet_sock *inet = inet_sk(sk);
791 struct ipv6_pinfo *np = inet6_sk(sk);
792 struct dccp_sock *dp = dccp_sk(sk);
Arnaud Ebalard20c59de2010-06-01 21:35:01 +0000793 struct in6_addr *saddr = NULL, *final_p, final;
Eric Dumazet45f6fad2015-11-29 19:37:57 -0800794 struct ipv6_txoptions *opt;
David S. Miller4c9483b2011-03-12 16:22:43 -0500795 struct flowi6 fl6;
Gerrit Renker73c9e022006-11-10 13:01:31 -0200796 struct dst_entry *dst;
797 int addr_type;
798 int err;
799
800 dp->dccps_role = DCCP_ROLE_CLIENT;
801
802 if (addr_len < SIN6_LEN_RFC2133)
803 return -EINVAL;
804
805 if (usin->sin6_family != AF_INET6)
806 return -EAFNOSUPPORT;
807
David S. Miller4c9483b2011-03-12 16:22:43 -0500808 memset(&fl6, 0, sizeof(fl6));
Gerrit Renker73c9e022006-11-10 13:01:31 -0200809
810 if (np->sndflow) {
David S. Miller4c9483b2011-03-12 16:22:43 -0500811 fl6.flowlabel = usin->sin6_flowinfo & IPV6_FLOWINFO_MASK;
812 IP6_ECN_flow_init(fl6.flowlabel);
813 if (fl6.flowlabel & IPV6_FLOWLABEL_MASK) {
Gerrit Renker73c9e022006-11-10 13:01:31 -0200814 struct ip6_flowlabel *flowlabel;
David S. Miller4c9483b2011-03-12 16:22:43 -0500815 flowlabel = fl6_sock_lookup(sk, fl6.flowlabel);
Gerrit Renker73c9e022006-11-10 13:01:31 -0200816 if (flowlabel == NULL)
817 return -EINVAL;
Gerrit Renker73c9e022006-11-10 13:01:31 -0200818 fl6_sock_release(flowlabel);
819 }
820 }
821 /*
822 * connect() to INADDR_ANY means loopback (BSD'ism).
823 */
824 if (ipv6_addr_any(&usin->sin6_addr))
825 usin->sin6_addr.s6_addr[15] = 1;
826
827 addr_type = ipv6_addr_type(&usin->sin6_addr);
828
829 if (addr_type & IPV6_ADDR_MULTICAST)
830 return -ENETUNREACH;
831
832 if (addr_type & IPV6_ADDR_LINKLOCAL) {
833 if (addr_len >= sizeof(struct sockaddr_in6) &&
834 usin->sin6_scope_id) {
835 /* If interface is set while binding, indices
836 * must coincide.
837 */
838 if (sk->sk_bound_dev_if &&
839 sk->sk_bound_dev_if != usin->sin6_scope_id)
840 return -EINVAL;
841
842 sk->sk_bound_dev_if = usin->sin6_scope_id;
843 }
844
845 /* Connect to link-local address requires an interface */
846 if (!sk->sk_bound_dev_if)
847 return -EINVAL;
848 }
849
Eric Dumazetefe42082013-10-03 15:42:29 -0700850 sk->sk_v6_daddr = usin->sin6_addr;
David S. Miller4c9483b2011-03-12 16:22:43 -0500851 np->flow_label = fl6.flowlabel;
Gerrit Renker73c9e022006-11-10 13:01:31 -0200852
853 /*
854 * DCCP over IPv4
855 */
856 if (addr_type == IPV6_ADDR_MAPPED) {
857 u32 exthdrlen = icsk->icsk_ext_hdr_len;
858 struct sockaddr_in sin;
859
860 SOCK_DEBUG(sk, "connect: ipv4 mapped\n");
861
862 if (__ipv6_only_sock(sk))
863 return -ENETUNREACH;
864
865 sin.sin_family = AF_INET;
866 sin.sin_port = usin->sin6_port;
867 sin.sin_addr.s_addr = usin->sin6_addr.s6_addr32[3];
868
869 icsk->icsk_af_ops = &dccp_ipv6_mapped;
870 sk->sk_backlog_rcv = dccp_v4_do_rcv;
871
872 err = dccp_v4_connect(sk, (struct sockaddr *)&sin, sizeof(sin));
873 if (err) {
874 icsk->icsk_ext_hdr_len = exthdrlen;
875 icsk->icsk_af_ops = &dccp_ipv6_af_ops;
876 sk->sk_backlog_rcv = dccp_v6_do_rcv;
877 goto failure;
Gerrit Renker73c9e022006-11-10 13:01:31 -0200878 }
Eric Dumazetd1e559d2015-03-18 14:05:35 -0700879 np->saddr = sk->sk_v6_rcv_saddr;
Gerrit Renker73c9e022006-11-10 13:01:31 -0200880 return err;
881 }
882
Eric Dumazetefe42082013-10-03 15:42:29 -0700883 if (!ipv6_addr_any(&sk->sk_v6_rcv_saddr))
884 saddr = &sk->sk_v6_rcv_saddr;
Gerrit Renker73c9e022006-11-10 13:01:31 -0200885
David S. Miller4c9483b2011-03-12 16:22:43 -0500886 fl6.flowi6_proto = IPPROTO_DCCP;
Eric Dumazetefe42082013-10-03 15:42:29 -0700887 fl6.daddr = sk->sk_v6_daddr;
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +0000888 fl6.saddr = saddr ? *saddr : np->saddr;
David S. Miller4c9483b2011-03-12 16:22:43 -0500889 fl6.flowi6_oif = sk->sk_bound_dev_if;
David S. Miller1958b852011-03-12 16:36:19 -0500890 fl6.fl6_dport = usin->sin6_port;
891 fl6.fl6_sport = inet->inet_sport;
David S. Miller4c9483b2011-03-12 16:22:43 -0500892 security_sk_classify_flow(sk, flowi6_to_flowi(&fl6));
Gerrit Renker73c9e022006-11-10 13:01:31 -0200893
Hannes Frederic Sowa1e1d04e2016-04-05 17:10:15 +0200894 opt = rcu_dereference_protected(np->opt, lockdep_sock_is_held(sk));
Eric Dumazet45f6fad2015-11-29 19:37:57 -0800895 final_p = fl6_update_dst(&fl6, opt, &final);
Gerrit Renker73c9e022006-11-10 13:01:31 -0200896
Sabrina Dubroca5cc5fa72019-12-04 15:35:52 +0100897 dst = ip6_dst_lookup_flow(sock_net(sk), sk, &fl6, final_p);
David S. Miller68d0c6d2011-03-01 13:19:07 -0800898 if (IS_ERR(dst)) {
899 err = PTR_ERR(dst);
Gerrit Renker73c9e022006-11-10 13:01:31 -0200900 goto failure;
David S. Miller14e50e52007-05-24 18:17:54 -0700901 }
Gerrit Renker73c9e022006-11-10 13:01:31 -0200902
903 if (saddr == NULL) {
David S. Miller4c9483b2011-03-12 16:22:43 -0500904 saddr = &fl6.saddr;
Eric Dumazetefe42082013-10-03 15:42:29 -0700905 sk->sk_v6_rcv_saddr = *saddr;
Gerrit Renker73c9e022006-11-10 13:01:31 -0200906 }
907
908 /* set the source address */
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +0000909 np->saddr = *saddr;
Eric Dumazetc720c7e2009-10-15 06:30:45 +0000910 inet->inet_rcv_saddr = LOOPBACK4_IPV6;
Gerrit Renker73c9e022006-11-10 13:01:31 -0200911
Eric Dumazet6bd4f352015-12-02 21:53:57 -0800912 ip6_dst_store(sk, dst, NULL, NULL);
Gerrit Renker73c9e022006-11-10 13:01:31 -0200913
914 icsk->icsk_ext_hdr_len = 0;
Eric Dumazet45f6fad2015-11-29 19:37:57 -0800915 if (opt)
916 icsk->icsk_ext_hdr_len = opt->opt_flen + opt->opt_nflen;
Gerrit Renker73c9e022006-11-10 13:01:31 -0200917
Eric Dumazetc720c7e2009-10-15 06:30:45 +0000918 inet->inet_dport = usin->sin6_port;
Gerrit Renker73c9e022006-11-10 13:01:31 -0200919
920 dccp_set_state(sk, DCCP_REQUESTING);
921 err = inet6_hash_connect(&dccp_death_row, sk);
922 if (err)
923 goto late_failure;
Gerrit Renkerd7f73652006-11-13 13:34:38 -0200924
925 dp->dccps_iss = secure_dccpv6_sequence_number(np->saddr.s6_addr32,
Eric Dumazetefe42082013-10-03 15:42:29 -0700926 sk->sk_v6_daddr.s6_addr32,
Eric Dumazetc720c7e2009-10-15 06:30:45 +0000927 inet->inet_sport,
928 inet->inet_dport);
Gerrit Renker73c9e022006-11-10 13:01:31 -0200929 err = dccp_connect(sk);
930 if (err)
931 goto late_failure;
932
933 return 0;
934
935late_failure:
936 dccp_set_state(sk, DCCP_CLOSED);
937 __sk_dst_reset(sk);
938failure:
Eric Dumazetc720c7e2009-10-15 06:30:45 +0000939 inet->inet_dport = 0;
Gerrit Renker73c9e022006-11-10 13:01:31 -0200940 sk->sk_route_caps = 0;
941 return err;
942}
943
Stephen Hemminger3b401a82009-09-01 19:25:04 +0000944static const struct inet_connection_sock_af_ops dccp_ipv6_af_ops = {
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -0800945 .queue_xmit = inet6_csk_xmit,
946 .send_check = dccp_v6_send_check,
947 .rebuild_header = inet6_sk_rebuild_header,
948 .conn_request = dccp_v6_conn_request,
949 .syn_recv_sock = dccp_v6_request_recv_sock,
950 .net_header_len = sizeof(struct ipv6hdr),
951 .setsockopt = ipv6_setsockopt,
952 .getsockopt = ipv6_getsockopt,
953 .addr2sockaddr = inet6_csk_addr2sockaddr,
954 .sockaddr_len = sizeof(struct sockaddr_in6),
Arnaldo Carvalho de Meloab1e0a12008-02-03 04:06:04 -0800955 .bind_conflict = inet6_csk_bind_conflict,
Dmitry Mishin3fdadf72006-03-20 22:45:21 -0800956#ifdef CONFIG_COMPAT
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -0800957 .compat_setsockopt = compat_ipv6_setsockopt,
958 .compat_getsockopt = compat_ipv6_getsockopt,
Dmitry Mishin3fdadf72006-03-20 22:45:21 -0800959#endif
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800960};
961
962/*
963 * DCCP over IPv4 via INET6 API
964 */
Stephen Hemminger3b401a82009-09-01 19:25:04 +0000965static const struct inet_connection_sock_af_ops dccp_ipv6_mapped = {
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -0800966 .queue_xmit = ip_queue_xmit,
967 .send_check = dccp_v4_send_check,
968 .rebuild_header = inet_sk_rebuild_header,
969 .conn_request = dccp_v6_conn_request,
970 .syn_recv_sock = dccp_v6_request_recv_sock,
971 .net_header_len = sizeof(struct iphdr),
972 .setsockopt = ipv6_setsockopt,
973 .getsockopt = ipv6_getsockopt,
974 .addr2sockaddr = inet6_csk_addr2sockaddr,
975 .sockaddr_len = sizeof(struct sockaddr_in6),
Eric Dumazet990ff4d2016-11-03 08:59:46 -0700976 .bind_conflict = inet6_csk_bind_conflict,
Dmitry Mishin3fdadf72006-03-20 22:45:21 -0800977#ifdef CONFIG_COMPAT
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -0800978 .compat_setsockopt = compat_ipv6_setsockopt,
979 .compat_getsockopt = compat_ipv6_getsockopt,
Dmitry Mishin3fdadf72006-03-20 22:45:21 -0800980#endif
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800981};
982
983/* NOTE: A lot of things set to zero explicitly by call to
984 * sk_alloc() so need not be done here.
985 */
986static int dccp_v6_init_sock(struct sock *sk)
987{
Arnaldo Carvalho de Melo72478872006-03-20 22:00:37 -0800988 static __u8 dccp_v6_ctl_sock_initialized;
989 int err = dccp_init_sock(sk, dccp_v6_ctl_sock_initialized);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800990
Arnaldo Carvalho de Melo72478872006-03-20 22:00:37 -0800991 if (err == 0) {
992 if (unlikely(!dccp_v6_ctl_sock_initialized))
993 dccp_v6_ctl_sock_initialized = 1;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800994 inet_csk(sk)->icsk_af_ops = &dccp_ipv6_af_ops;
Arnaldo Carvalho de Melo72478872006-03-20 22:00:37 -0800995 }
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800996
997 return err;
998}
999
Brian Haley7d06b2e2008-06-14 17:04:49 -07001000static void dccp_v6_destroy_sock(struct sock *sk)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001001{
Arnaldo Carvalho de Melo3e0fadc2006-03-20 21:23:15 -08001002 dccp_destroy_sock(sk);
Brian Haley7d06b2e2008-06-14 17:04:49 -07001003 inet6_destroy_sock(sk);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001004}
1005
Gerrit Renker73c9e022006-11-10 13:01:31 -02001006static struct timewait_sock_ops dccp6_timewait_sock_ops = {
1007 .twsk_obj_size = sizeof(struct dccp6_timewait_sock),
1008};
1009
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001010static struct proto dccp_v6_prot = {
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001011 .name = "DCCPv6",
1012 .owner = THIS_MODULE,
1013 .close = dccp_close,
1014 .connect = dccp_v6_connect,
1015 .disconnect = dccp_disconnect,
1016 .ioctl = dccp_ioctl,
1017 .init = dccp_v6_init_sock,
1018 .setsockopt = dccp_setsockopt,
1019 .getsockopt = dccp_getsockopt,
1020 .sendmsg = dccp_sendmsg,
1021 .recvmsg = dccp_recvmsg,
1022 .backlog_rcv = dccp_v6_do_rcv,
Craig Gallek496611d2016-02-10 11:50:36 -05001023 .hash = inet6_hash,
Arnaldo Carvalho de Meloab1e0a12008-02-03 04:06:04 -08001024 .unhash = inet_unhash,
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001025 .accept = inet_csk_accept,
Arnaldo Carvalho de Meloab1e0a12008-02-03 04:06:04 -08001026 .get_port = inet_csk_get_port,
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001027 .shutdown = dccp_shutdown,
1028 .destroy = dccp_v6_destroy_sock,
1029 .orphan_count = &dccp_orphan_count,
1030 .max_header = MAX_DCCP_HEADER,
1031 .obj_size = sizeof(struct dccp6_sock),
Eric Dumazet3ab5aee2008-11-16 19:40:17 -08001032 .slab_flags = SLAB_DESTROY_BY_RCU,
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001033 .rsk_prot = &dccp6_request_sock_ops,
1034 .twsk_prot = &dccp6_timewait_sock_ops,
Pavel Emelyanov39d8cda2008-03-22 16:50:58 -07001035 .h.hashinfo = &dccp_hashinfo,
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001036#ifdef CONFIG_COMPAT
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001037 .compat_setsockopt = compat_dccp_setsockopt,
1038 .compat_getsockopt = compat_dccp_getsockopt,
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001039#endif
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001040};
1041
Alexey Dobriyan41135cc2009-09-14 12:22:28 +00001042static const struct inet6_protocol dccp_v6_protocol = {
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -08001043 .handler = dccp_v6_rcv,
1044 .err_handler = dccp_v6_err,
1045 .flags = INET6_PROTO_NOPOLICY | INET6_PROTO_FINAL,
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001046};
1047
Alexey Dobriyan5708e862009-09-14 12:23:23 +00001048static const struct proto_ops inet6_dccp_ops = {
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001049 .family = PF_INET6,
1050 .owner = THIS_MODULE,
1051 .release = inet6_release,
1052 .bind = inet6_bind,
1053 .connect = inet_stream_connect,
1054 .socketpair = sock_no_socketpair,
1055 .accept = inet_accept,
1056 .getname = inet6_getname,
1057 .poll = dccp_poll,
1058 .ioctl = inet6_ioctl,
1059 .listen = inet_dccp_listen,
1060 .shutdown = inet_shutdown,
1061 .setsockopt = sock_common_setsockopt,
1062 .getsockopt = sock_common_getsockopt,
1063 .sendmsg = inet_sendmsg,
1064 .recvmsg = sock_common_recvmsg,
1065 .mmap = sock_no_mmap,
1066 .sendpage = sock_no_sendpage,
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001067#ifdef CONFIG_COMPAT
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001068 .compat_setsockopt = compat_sock_common_setsockopt,
1069 .compat_getsockopt = compat_sock_common_getsockopt,
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001070#endif
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001071};
1072
1073static struct inet_protosw dccp_v6_protosw = {
1074 .type = SOCK_DCCP,
1075 .protocol = IPPROTO_DCCP,
1076 .prot = &dccp_v6_prot,
1077 .ops = &inet6_dccp_ops,
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -08001078 .flags = INET_PROTOSW_ICSK,
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001079};
1080
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00001081static int __net_init dccp_v6_init_net(struct net *net)
Pavel Emelyanov8231bd22008-04-13 22:32:02 -07001082{
Gerrit Renkerd14a0eb2010-03-14 20:13:19 +00001083 if (dccp_hashinfo.bhash == NULL)
1084 return -ESOCKTNOSUPPORT;
Pavel Emelyanov334527d2008-04-13 22:32:45 -07001085
Gerrit Renkerd14a0eb2010-03-14 20:13:19 +00001086 return inet_ctl_sock_create(&net->dccp.v6_ctl_sk, PF_INET6,
1087 SOCK_DCCP, IPPROTO_DCCP, net);
Pavel Emelyanov8231bd22008-04-13 22:32:02 -07001088}
1089
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00001090static void __net_exit dccp_v6_exit_net(struct net *net)
Pavel Emelyanov8231bd22008-04-13 22:32:02 -07001091{
Pavel Emelyanov334527d2008-04-13 22:32:45 -07001092 inet_ctl_sock_destroy(net->dccp.v6_ctl_sk);
Pavel Emelyanov8231bd22008-04-13 22:32:02 -07001093}
1094
1095static struct pernet_operations dccp_v6_ops = {
1096 .init = dccp_v6_init_net,
1097 .exit = dccp_v6_exit_net,
1098};
1099
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001100static int __init dccp_v6_init(void)
1101{
1102 int err = proto_register(&dccp_v6_prot, 1);
1103
1104 if (err != 0)
1105 goto out;
1106
1107 err = inet6_add_protocol(&dccp_v6_protocol, IPPROTO_DCCP);
1108 if (err != 0)
1109 goto out_unregister_proto;
1110
1111 inet6_register_protosw(&dccp_v6_protosw);
Arnaldo Carvalho de Melo72478872006-03-20 22:00:37 -08001112
Pavel Emelyanov8231bd22008-04-13 22:32:02 -07001113 err = register_pernet_subsys(&dccp_v6_ops);
1114 if (err != 0)
1115 goto out_destroy_ctl_sock;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001116out:
1117 return err;
Pavel Emelyanov8231bd22008-04-13 22:32:02 -07001118
1119out_destroy_ctl_sock:
Arnaldo Carvalho de Melo72478872006-03-20 22:00:37 -08001120 inet6_del_protocol(&dccp_v6_protocol, IPPROTO_DCCP);
1121 inet6_unregister_protosw(&dccp_v6_protosw);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001122out_unregister_proto:
1123 proto_unregister(&dccp_v6_prot);
1124 goto out;
1125}
1126
1127static void __exit dccp_v6_exit(void)
1128{
Pavel Emelyanov8231bd22008-04-13 22:32:02 -07001129 unregister_pernet_subsys(&dccp_v6_ops);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001130 inet6_del_protocol(&dccp_v6_protocol, IPPROTO_DCCP);
1131 inet6_unregister_protosw(&dccp_v6_protosw);
1132 proto_unregister(&dccp_v6_prot);
1133}
1134
1135module_init(dccp_v6_init);
1136module_exit(dccp_v6_exit);
1137
1138/*
1139 * __stringify doesn't likes enums, so use SOCK_DCCP (6) and IPPROTO_DCCP (33)
1140 * values directly, Also cover the case where the protocol is not specified,
1141 * i.e. net-pf-PF_INET6-proto-0-type-SOCK_DCCP
1142 */
Jean Delvare7131c6c2007-10-21 16:45:03 -07001143MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_INET6, 33, 6);
1144MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_INET6, 0, 6);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001145MODULE_LICENSE("GPL");
1146MODULE_AUTHOR("Arnaldo Carvalho de Melo <acme@mandriva.com>");
1147MODULE_DESCRIPTION("DCCPv6 - Datagram Congestion Controlled Protocol");