blob: 87c513b5ff2eb2313db4d1f8c404a99d9aa201aa [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
Steffen Klassert0e0d44a2013-08-28 08:04:14 +0200212 dst = ip6_dst_lookup_flow(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. */
Steffen Klassert0e0d44a2013-08-28 08:04:14 +0200283 dst = ip6_dst_lookup_flow(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
320 if (dccp_bad_service_code(sk, service)) {
Gerrit Renker4a5409a2007-10-04 14:52:28 -0700321 dcb->dccpd_reset_code = DCCP_RESET_CODE_BAD_SERVICE_CODE;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800322 goto drop;
Arnaldo Carvalho de Melo8109b022006-12-10 16:01:18 -0200323 }
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800324 /*
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800325 * There are no SYN attacks on IPv6, yet...
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800326 */
Gerrit Renker4a5409a2007-10-04 14:52:28 -0700327 dcb->dccpd_reset_code = DCCP_RESET_CODE_TOO_BUSY;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800328 if (inet_csk_reqsk_queue_is_full(sk))
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800329 goto drop;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800330
Eric Dumazetdfe4f692016-10-26 09:27:57 -0700331 if (sk_acceptq_is_full(sk))
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800332 goto drop;
333
Eric Dumazeta1a53442015-10-04 21:08:11 -0700334 req = inet_reqsk_alloc(&dccp6_request_sock_ops, sk, true);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800335 if (req == NULL)
336 goto drop;
337
Gerrit Renkerac757732008-11-04 23:55:49 -0800338 if (dccp_reqsk_init(req, dccp_sk(sk), skb))
339 goto drop_and_free;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800340
Gerrit Renker8b819412007-12-13 12:29:24 -0200341 dreq = dccp_rsk(req);
342 if (dccp_parse_options(sk, dreq, skb))
343 goto drop_and_free;
344
Venkat Yekkirala4237c752006-07-24 23:32:50 -0700345 if (security_inet_conn_request(sk, skb, req))
346 goto drop_and_free;
347
Eric Dumazet634fb9792013-10-09 15:21:29 -0700348 ireq = inet_rsk(req);
349 ireq->ir_v6_rmt_addr = ipv6_hdr(skb)->saddr;
350 ireq->ir_v6_loc_addr = ipv6_hdr(skb)->daddr;
Eric Dumazet3f66b082015-03-12 16:44:10 -0700351 ireq->ireq_family = AF_INET6;
Eric Dumazet543cb052018-04-07 13:42:41 -0700352 ireq->ir_mark = inet_request_mark(sk, skb);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800353
Eric Dumazeta2247722014-09-27 09:50:56 -0700354 if (ipv6_opt_accepted(sk, skb, IP6CB(skb)) ||
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800355 np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo ||
356 np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim) {
357 atomic_inc(&skb->users);
Eric Dumazet634fb9792013-10-09 15:21:29 -0700358 ireq->pktopts = skb;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800359 }
Eric Dumazet634fb9792013-10-09 15:21:29 -0700360 ireq->ir_iif = sk->sk_bound_dev_if;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800361
362 /* So that link locals have meaning */
363 if (!sk->sk_bound_dev_if &&
Eric Dumazet634fb9792013-10-09 15:21:29 -0700364 ipv6_addr_type(&ireq->ir_v6_rmt_addr) & IPV6_ADDR_LINKLOCAL)
365 ireq->ir_iif = inet6_iif(skb);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800366
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800367 /*
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800368 * Step 3: Process LISTEN state
369 *
Gerrit Renkerd83ca5a2006-11-10 16:29:14 -0200370 * Set S.ISR, S.GSR, S.SWL, S.SWH from packet or Init Cookie
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800371 *
Samuel Jerof541fb72012-02-26 18:22:02 -0700372 * Setting S.SWL/S.SWH to is deferred to dccp_create_openreq_child().
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800373 */
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800374 dreq->dreq_isr = dcb->dccpd_seq;
Samuel Jerof541fb72012-02-26 18:22:02 -0700375 dreq->dreq_gsr = dreq->dreq_isr;
Gerrit Renker865e9022006-11-13 13:31:50 -0200376 dreq->dreq_iss = dccp_v6_init_sequence(skb);
Samuel Jerof541fb72012-02-26 18:22:02 -0700377 dreq->dreq_gss = dreq->dreq_iss;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800378 dreq->dreq_service = service;
379
Christoph Paasch1a2c6182013-03-17 08:23:34 +0000380 if (dccp_v6_send_response(sk, req))
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800381 goto drop_and_free;
382
Eric Dumazet079096f2015-10-02 11:43:32 -0700383 inet_csk_reqsk_queue_hash_add(sk, req, DCCP_TIMEOUT_INIT);
Xin Long9ffa6722017-07-26 14:19:09 +0800384 reqsk_put(req);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800385 return 0;
386
387drop_and_free:
388 reqsk_free(req);
389drop:
Eric Dumazetaa62d762016-04-27 16:44:28 -0700390 __DCCP_INC_STATS(DCCP_MIB_ATTEMPTFAILS);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800391 return -1;
392}
393
Eric Dumazet0c271712015-09-29 07:42:48 -0700394static struct sock *dccp_v6_request_recv_sock(const struct sock *sk,
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800395 struct sk_buff *skb,
396 struct request_sock *req,
Eric Dumazet5e0724d2015-10-22 08:20:46 -0700397 struct dst_entry *dst,
398 struct request_sock *req_unhash,
399 bool *own_req)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800400{
Eric Dumazet634fb9792013-10-09 15:21:29 -0700401 struct inet_request_sock *ireq = inet_rsk(req);
Eric Dumazet0c271712015-09-29 07:42:48 -0700402 struct ipv6_pinfo *newnp;
403 const struct ipv6_pinfo *np = inet6_sk(sk);
Eric Dumazet45f6fad2015-11-29 19:37:57 -0800404 struct ipv6_txoptions *opt;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800405 struct inet_sock *newinet;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800406 struct dccp6_sock *newdp6;
407 struct sock *newsk;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800408
409 if (skb->protocol == htons(ETH_P_IP)) {
410 /*
411 * v6 mapped
412 */
Eric Dumazet5e0724d2015-10-22 08:20:46 -0700413 newsk = dccp_v4_request_recv_sock(sk, skb, req, dst,
414 req_unhash, own_req);
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800415 if (newsk == NULL)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800416 return NULL;
417
418 newdp6 = (struct dccp6_sock *)newsk;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800419 newinet = inet_sk(newsk);
420 newinet->pinet6 = &newdp6->inet6;
421 newnp = inet6_sk(newsk);
422
423 memcpy(newnp, np, sizeof(struct ipv6_pinfo));
424
Eric Dumazetd1e559d2015-03-18 14:05:35 -0700425 newnp->saddr = newsk->sk_v6_rcv_saddr;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800426
427 inet_csk(newsk)->icsk_af_ops = &dccp_ipv6_mapped;
428 newsk->sk_backlog_rcv = dccp_v4_do_rcv;
429 newnp->pktoptions = NULL;
430 newnp->opt = NULL;
WANG Cong4bd8f5e2017-05-09 16:59:54 -0700431 newnp->ipv6_mc_list = NULL;
432 newnp->ipv6_ac_list = NULL;
433 newnp->ipv6_fl_list = NULL;
Eric Dumazetdc8390f2019-03-19 05:46:18 -0700434 newnp->mcast_oif = inet_iif(skb);
435 newnp->mcast_hops = ip_hdr(skb)->ttl;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800436
437 /*
438 * No need to charge this sock to the relevant IPv6 refcnt debug socks count
439 * here, dccp_create_openreq_child now does this for us, see the comment in
440 * that function for the gory details. -acme
441 */
442
443 /* It is tricky place. Until this moment IPv4 tcp
444 worked with IPv6 icsk.icsk_af_ops.
445 Sync it now.
446 */
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -0800447 dccp_sync_mss(newsk, inet_csk(newsk)->icsk_pmtu_cookie);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800448
449 return newsk;
450 }
451
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800452
453 if (sk_acceptq_is_full(sk))
454 goto out_overflow;
455
Eric Dumazetf76b33c2015-09-29 07:42:42 -0700456 if (!dst) {
David S. Miller4c9483b2011-03-12 16:22:43 -0500457 struct flowi6 fl6;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800458
Eric Dumazetf76b33c2015-09-29 07:42:42 -0700459 dst = inet6_csk_route_req(sk, &fl6, req, IPPROTO_DCCP);
460 if (!dst)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800461 goto out;
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800462 }
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800463
464 newsk = dccp_create_openreq_child(sk, req, skb);
465 if (newsk == NULL)
Balazs Scheidler093d2822010-10-21 13:06:43 +0200466 goto out_nonewsk;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800467
468 /*
469 * No need to charge this sock to the relevant IPv6 refcnt debug socks
470 * count here, dccp_create_openreq_child now does this for us, see the
471 * comment in that function for the gory details. -acme
472 */
473
Eric Dumazet6bd4f352015-12-02 21:53:57 -0800474 ip6_dst_store(newsk, dst, NULL, NULL);
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800475 newsk->sk_route_caps = dst->dev->features & ~(NETIF_F_IP_CSUM |
476 NETIF_F_TSO);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800477 newdp6 = (struct dccp6_sock *)newsk;
478 newinet = inet_sk(newsk);
479 newinet->pinet6 = &newdp6->inet6;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800480 newnp = inet6_sk(newsk);
481
482 memcpy(newnp, np, sizeof(struct ipv6_pinfo));
483
Eric Dumazet634fb9792013-10-09 15:21:29 -0700484 newsk->sk_v6_daddr = ireq->ir_v6_rmt_addr;
485 newnp->saddr = ireq->ir_v6_loc_addr;
486 newsk->sk_v6_rcv_saddr = ireq->ir_v6_loc_addr;
487 newsk->sk_bound_dev_if = ireq->ir_iif;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800488
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800489 /* Now IPv6 options...
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800490
491 First: no IPv4 options.
492 */
Eric Dumazetf6d8bd02011-04-21 09:45:37 +0000493 newinet->inet_opt = NULL;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800494
495 /* Clone RX bits */
496 newnp->rxopt.all = np->rxopt.all;
497
WANG Cong4bd8f5e2017-05-09 16:59:54 -0700498 newnp->ipv6_mc_list = NULL;
499 newnp->ipv6_ac_list = NULL;
500 newnp->ipv6_fl_list = NULL;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800501 newnp->pktoptions = NULL;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800502 newnp->opt = NULL;
503 newnp->mcast_oif = inet6_iif(skb);
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700504 newnp->mcast_hops = ipv6_hdr(skb)->hop_limit;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800505
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800506 /*
507 * Clone native IPv6 options from listening socket (if any)
508 *
509 * Yes, keeping reference count would be much more clever, but we make
510 * one more one thing there: reattach optmem to newsk.
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800511 */
Huw Davies56ac42b2016-06-27 15:05:28 -0400512 opt = ireq->ipv6_opt;
513 if (!opt)
514 opt = rcu_dereference(np->opt);
Eric Dumazet45f6fad2015-11-29 19:37:57 -0800515 if (opt) {
516 opt = ipv6_dup_options(newsk, opt);
517 RCU_INIT_POINTER(newnp->opt, opt);
518 }
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -0800519 inet_csk(newsk)->icsk_ext_hdr_len = 0;
Eric Dumazet45f6fad2015-11-29 19:37:57 -0800520 if (opt)
521 inet_csk(newsk)->icsk_ext_hdr_len = opt->opt_nflen +
522 opt->opt_flen;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800523
524 dccp_sync_mss(newsk, dst_mtu(dst));
525
Eric Dumazetc720c7e2009-10-15 06:30:45 +0000526 newinet->inet_daddr = newinet->inet_saddr = LOOPBACK4_IPV6;
527 newinet->inet_rcv_saddr = LOOPBACK4_IPV6;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800528
Balazs Scheidler093d2822010-10-21 13:06:43 +0200529 if (__inet_inherit_port(sk, newsk) < 0) {
Christoph Paasche337e242012-12-14 04:07:58 +0000530 inet_csk_prepare_forced_close(newsk);
531 dccp_done(newsk);
Balazs Scheidler093d2822010-10-21 13:06:43 +0200532 goto out;
533 }
Eric Dumazet5e0724d2015-10-22 08:20:46 -0700534 *own_req = inet_ehash_nolisten(newsk, req_to_sk(req_unhash));
Eric Dumazetce105002015-10-30 09:46:12 -0700535 /* Clone pktoptions received with SYN, if we own the req */
536 if (*own_req && ireq->pktopts) {
537 newnp->pktoptions = skb_clone(ireq->pktopts, GFP_ATOMIC);
538 consume_skb(ireq->pktopts);
539 ireq->pktopts = NULL;
540 if (newnp->pktoptions)
541 skb_set_owner_r(newnp->pktoptions, newsk);
542 }
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800543
544 return newsk;
545
546out_overflow:
Eric Dumazet02a1d6e2016-04-27 16:44:39 -0700547 __NET_INC_STATS(sock_net(sk), LINUX_MIB_LISTENOVERFLOWS);
Balazs Scheidler093d2822010-10-21 13:06:43 +0200548out_nonewsk:
549 dst_release(dst);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800550out:
Eric Dumazet02a1d6e2016-04-27 16:44:39 -0700551 __NET_INC_STATS(sock_net(sk), LINUX_MIB_LISTENDROPS);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800552 return NULL;
553}
554
555/* The socket must have it's spinlock held when we get
556 * here.
557 *
558 * We have a potential double-lock case here, so even when
559 * doing backlog processing we use the BH locking scheme.
560 * This is because we cannot sleep with the original spinlock
561 * held.
562 */
563static int dccp_v6_do_rcv(struct sock *sk, struct sk_buff *skb)
564{
565 struct ipv6_pinfo *np = inet6_sk(sk);
566 struct sk_buff *opt_skb = NULL;
567
568 /* Imagine: socket is IPv6. IPv4 packet arrives,
569 goes to IPv4 receive handler and backlogged.
570 From backlog it always goes here. Kerboom...
571 Fortunately, dccp_rcv_established and rcv_established
572 handle them correctly, but it is not case with
573 dccp_v6_hnd_req and dccp_v6_ctl_send_reset(). --ANK
574 */
575
576 if (skb->protocol == htons(ETH_P_IP))
577 return dccp_v4_do_rcv(sk, skb);
578
Dmitry Mishinfda9ef52006-08-31 15:28:39 -0700579 if (sk_filter(sk, skb))
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800580 goto discard;
581
582 /*
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800583 * socket locking is here for SMP purposes as backlog rcv is currently
584 * called with bh processing disabled.
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800585 */
586
587 /* Do Stevens' IPV6_PKTOPTIONS.
588
589 Yes, guys, it is the only place in our code, where we
590 may make it not affecting IPv4.
591 The rest of code is protocol independent,
592 and I do not like idea to uglify IPv4.
593
594 Actually, all the idea behind IPV6_PKTOPTIONS
595 looks not very well thought. For now we latch
596 options, received in the last packet, enqueued
597 by tcp. Feel free to propose better solution.
YOSHIFUJI Hideakic9eaf172007-02-09 23:24:38 +0900598 --ANK (980728)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800599 */
600 if (np->rxopt.all)
Gerrit Renker89e7e572006-11-10 11:13:33 -0200601 /*
602 * FIXME: Add handling of IPV6_PKTOPTIONS skb. See the comments below
603 * (wrt ipv6_pktopions) and net/ipv6/tcp_ipv6.c for an example.
604 */
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800605 opt_skb = skb_clone(skb, GFP_ATOMIC);
606
607 if (sk->sk_state == DCCP_OPEN) { /* Fast path */
608 if (dccp_rcv_established(sk, skb, dccp_hdr(skb), skb->len))
609 goto reset;
David S. Millerfd169f12006-10-20 19:44:17 -0700610 if (opt_skb) {
Gerrit Renker89e7e572006-11-10 11:13:33 -0200611 /* XXX This is where we would goto ipv6_pktoptions. */
David S. Millerfd169f12006-10-20 19:44:17 -0700612 __kfree_skb(opt_skb);
613 }
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800614 return 0;
615 }
616
Gerrit Renkerd83ca5a2006-11-10 16:29:14 -0200617 /*
618 * Step 3: Process LISTEN state
619 * If S.state == LISTEN,
620 * If P.type == Request or P contains a valid Init Cookie option,
621 * (* Must scan the packet's options to check for Init
622 * Cookies. Only Init Cookies are processed here,
623 * however; other options are processed in Step 8. This
624 * scan need only be performed if the endpoint uses Init
625 * Cookies *)
626 * (* Generate a new socket and switch to that socket *)
627 * Set S := new socket for this port pair
628 * S.state = RESPOND
629 * Choose S.ISS (initial seqno) or set from Init Cookies
630 * Initialize S.GAR := S.ISS
631 * Set S.ISR, S.GSR, S.SWL, S.SWH from packet or Init Cookies
632 * Continue with S.state == RESPOND
633 * (* A Response packet will be generated in Step 11 *)
634 * Otherwise,
635 * Generate Reset(No Connection) unless P.type == Reset
636 * Drop packet and return
637 *
638 * NOTE: the check for the packet types is done in
639 * dccp_rcv_state_process
640 */
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800641
642 if (dccp_rcv_state_process(sk, skb, dccp_hdr(skb), skb->len))
643 goto reset;
David S. Millerfd169f12006-10-20 19:44:17 -0700644 if (opt_skb) {
Gerrit Renker89e7e572006-11-10 11:13:33 -0200645 /* XXX This is where we would goto ipv6_pktoptions. */
David S. Millerfd169f12006-10-20 19:44:17 -0700646 __kfree_skb(opt_skb);
647 }
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800648 return 0;
649
650reset:
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800651 dccp_v6_ctl_send_reset(sk, skb);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800652discard:
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800653 if (opt_skb != NULL)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800654 __kfree_skb(opt_skb);
655 kfree_skb(skb);
656 return 0;
657}
658
Herbert Xue5bbef22007-10-15 12:50:28 -0700659static int dccp_v6_rcv(struct sk_buff *skb)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800660{
661 const struct dccp_hdr *dh;
Eric Dumazet3b24d852016-04-01 08:52:17 -0700662 bool refcounted;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800663 struct sock *sk;
Gerrit Renker6f4e5ff2006-11-10 17:43:06 -0200664 int min_cov;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800665
Gerrit Renker6f4e5ff2006-11-10 17:43:06 -0200666 /* Step 1: Check header basics */
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800667
668 if (dccp_invalid_packet(skb))
669 goto discard_it;
670
Gerrit Renker6f4e5ff2006-11-10 17:43:06 -0200671 /* Step 1: If header checksum is incorrect, drop packet and return. */
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700672 if (dccp_v6_csum_finish(skb, &ipv6_hdr(skb)->saddr,
673 &ipv6_hdr(skb)->daddr)) {
Gerrit Renker59348b12006-11-20 18:39:23 -0200674 DCCP_WARN("dropped packet with invalid checksum\n");
Gerrit Renker6f4e5ff2006-11-10 17:43:06 -0200675 goto discard_it;
676 }
677
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800678 dh = dccp_hdr(skb);
679
Gerrit Renkerfde20102007-10-24 10:12:09 -0200680 DCCP_SKB_CB(skb)->dccpd_seq = dccp_hdr_seq(dh);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800681 DCCP_SKB_CB(skb)->dccpd_type = dh->dccph_type;
682
683 if (dccp_packet_without_ack(skb))
684 DCCP_SKB_CB(skb)->dccpd_ack_seq = DCCP_PKT_WITHOUT_ACK_SEQ;
685 else
686 DCCP_SKB_CB(skb)->dccpd_ack_seq = dccp_hdr_ack_seq(skb);
687
Eric Dumazet4bdc3d62015-10-13 17:12:54 -0700688lookup:
Craig Galleka5836362016-02-10 11:50:38 -0500689 sk = __inet6_lookup_skb(&dccp_hashinfo, skb, __dccp_hdr_len(dh),
Eric Dumazet870c3152014-10-17 09:17:20 -0700690 dh->dccph_sport, dh->dccph_dport,
Eric Dumazet3b24d852016-04-01 08:52:17 -0700691 inet6_iif(skb), &refcounted);
Eric Dumazet4bdc3d62015-10-13 17:12:54 -0700692 if (!sk) {
Gerrit Renkerd23c7102006-11-10 11:46:34 -0200693 dccp_pr_debug("failed to look up flow ID in table and "
694 "get corresponding socket\n");
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800695 goto no_dccp_socket;
Gerrit Renkerd23c7102006-11-10 11:46:34 -0200696 }
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800697
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800698 /*
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800699 * Step 2:
Arnaldo Carvalho de Melo8109b022006-12-10 16:01:18 -0200700 * ... or S.state == TIMEWAIT,
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800701 * Generate Reset(No Connection) unless P.type == Reset
702 * Drop packet and return
703 */
Gerrit Renkerd23c7102006-11-10 11:46:34 -0200704 if (sk->sk_state == DCCP_TIME_WAIT) {
705 dccp_pr_debug("sk->sk_state == DCCP_TIME_WAIT: do_time_wait\n");
706 inet_twsk_put(inet_twsk(sk));
707 goto no_dccp_socket;
708 }
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800709
Eric Dumazet079096f2015-10-02 11:43:32 -0700710 if (sk->sk_state == DCCP_NEW_SYN_RECV) {
711 struct request_sock *req = inet_reqsk(sk);
Eric Dumazet77166822016-02-18 05:39:18 -0800712 struct sock *nsk;
Eric Dumazet079096f2015-10-02 11:43:32 -0700713
714 sk = req->rsk_listener;
Eric Dumazet77166822016-02-18 05:39:18 -0800715 if (unlikely(sk->sk_state != DCCP_LISTEN)) {
Eric Dumazetf03f2e12015-10-14 11:16:27 -0700716 inet_csk_reqsk_queue_drop_and_put(sk, req);
Eric Dumazet4bdc3d62015-10-13 17:12:54 -0700717 goto lookup;
718 }
Eric Dumazet77166822016-02-18 05:39:18 -0800719 sock_hold(sk);
Eric Dumazet3b24d852016-04-01 08:52:17 -0700720 refcounted = true;
Eric Dumazet77166822016-02-18 05:39:18 -0800721 nsk = dccp_check_req(sk, skb, req);
Eric Dumazet079096f2015-10-02 11:43:32 -0700722 if (!nsk) {
723 reqsk_put(req);
Eric Dumazet77166822016-02-18 05:39:18 -0800724 goto discard_and_relse;
Eric Dumazet079096f2015-10-02 11:43:32 -0700725 }
726 if (nsk == sk) {
Eric Dumazet079096f2015-10-02 11:43:32 -0700727 reqsk_put(req);
728 } else if (dccp_child_process(sk, nsk, skb)) {
729 dccp_v6_ctl_send_reset(sk, skb);
Eric Dumazet77166822016-02-18 05:39:18 -0800730 goto discard_and_relse;
Eric Dumazet079096f2015-10-02 11:43:32 -0700731 } else {
Eric Dumazet77166822016-02-18 05:39:18 -0800732 sock_put(sk);
Eric Dumazet079096f2015-10-02 11:43:32 -0700733 return 0;
734 }
735 }
Gerrit Renker6f4e5ff2006-11-10 17:43:06 -0200736 /*
737 * RFC 4340, sec. 9.2.1: Minimum Checksum Coverage
Arnaldo Carvalho de Melo8109b022006-12-10 16:01:18 -0200738 * o if MinCsCov = 0, only packets with CsCov = 0 are accepted
739 * o if MinCsCov > 0, also accept packets with CsCov >= MinCsCov
Gerrit Renker6f4e5ff2006-11-10 17:43:06 -0200740 */
741 min_cov = dccp_sk(sk)->dccps_pcrlen;
742 if (dh->dccph_cscov && (min_cov == 0 || dh->dccph_cscov < min_cov)) {
743 dccp_pr_debug("Packet CsCov %d does not satisfy MinCsCov %d\n",
744 dh->dccph_cscov, min_cov);
745 /* FIXME: send Data Dropped option (see also dccp_v4_rcv) */
746 goto discard_and_relse;
747 }
748
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800749 if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb))
750 goto discard_and_relse;
751
Eric Dumazetc3f24cf2016-11-02 17:14:41 -0700752 return __sk_receive_skb(sk, skb, 1, dh->dccph_doff * 4,
753 refcounted) ? -1 : 0;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800754
755no_dccp_socket:
756 if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb))
757 goto discard_it;
758 /*
759 * Step 2:
Arnaldo Carvalho de Melo8109b022006-12-10 16:01:18 -0200760 * If no socket ...
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800761 * Generate Reset(No Connection) unless P.type == Reset
762 * Drop packet and return
763 */
764 if (dh->dccph_type != DCCP_PKT_RESET) {
765 DCCP_SKB_CB(skb)->dccpd_reset_code =
766 DCCP_RESET_CODE_NO_CONNECTION;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800767 dccp_v6_ctl_send_reset(sk, skb);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800768 }
Gerrit Renkerd23c7102006-11-10 11:46:34 -0200769
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800770discard_it:
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800771 kfree_skb(skb);
772 return 0;
773
774discard_and_relse:
Eric Dumazet3b24d852016-04-01 08:52:17 -0700775 if (refcounted)
776 sock_put(sk);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800777 goto discard_it;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800778}
779
Gerrit Renker73c9e022006-11-10 13:01:31 -0200780static int dccp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
781 int addr_len)
782{
783 struct sockaddr_in6 *usin = (struct sockaddr_in6 *)uaddr;
784 struct inet_connection_sock *icsk = inet_csk(sk);
785 struct inet_sock *inet = inet_sk(sk);
786 struct ipv6_pinfo *np = inet6_sk(sk);
787 struct dccp_sock *dp = dccp_sk(sk);
Arnaud Ebalard20c59de2010-06-01 21:35:01 +0000788 struct in6_addr *saddr = NULL, *final_p, final;
Eric Dumazet45f6fad2015-11-29 19:37:57 -0800789 struct ipv6_txoptions *opt;
David S. Miller4c9483b2011-03-12 16:22:43 -0500790 struct flowi6 fl6;
Gerrit Renker73c9e022006-11-10 13:01:31 -0200791 struct dst_entry *dst;
792 int addr_type;
793 int err;
794
795 dp->dccps_role = DCCP_ROLE_CLIENT;
796
797 if (addr_len < SIN6_LEN_RFC2133)
798 return -EINVAL;
799
800 if (usin->sin6_family != AF_INET6)
801 return -EAFNOSUPPORT;
802
David S. Miller4c9483b2011-03-12 16:22:43 -0500803 memset(&fl6, 0, sizeof(fl6));
Gerrit Renker73c9e022006-11-10 13:01:31 -0200804
805 if (np->sndflow) {
David S. Miller4c9483b2011-03-12 16:22:43 -0500806 fl6.flowlabel = usin->sin6_flowinfo & IPV6_FLOWINFO_MASK;
807 IP6_ECN_flow_init(fl6.flowlabel);
808 if (fl6.flowlabel & IPV6_FLOWLABEL_MASK) {
Gerrit Renker73c9e022006-11-10 13:01:31 -0200809 struct ip6_flowlabel *flowlabel;
David S. Miller4c9483b2011-03-12 16:22:43 -0500810 flowlabel = fl6_sock_lookup(sk, fl6.flowlabel);
Gerrit Renker73c9e022006-11-10 13:01:31 -0200811 if (flowlabel == NULL)
812 return -EINVAL;
Gerrit Renker73c9e022006-11-10 13:01:31 -0200813 fl6_sock_release(flowlabel);
814 }
815 }
816 /*
817 * connect() to INADDR_ANY means loopback (BSD'ism).
818 */
819 if (ipv6_addr_any(&usin->sin6_addr))
820 usin->sin6_addr.s6_addr[15] = 1;
821
822 addr_type = ipv6_addr_type(&usin->sin6_addr);
823
824 if (addr_type & IPV6_ADDR_MULTICAST)
825 return -ENETUNREACH;
826
827 if (addr_type & IPV6_ADDR_LINKLOCAL) {
828 if (addr_len >= sizeof(struct sockaddr_in6) &&
829 usin->sin6_scope_id) {
830 /* If interface is set while binding, indices
831 * must coincide.
832 */
833 if (sk->sk_bound_dev_if &&
834 sk->sk_bound_dev_if != usin->sin6_scope_id)
835 return -EINVAL;
836
837 sk->sk_bound_dev_if = usin->sin6_scope_id;
838 }
839
840 /* Connect to link-local address requires an interface */
841 if (!sk->sk_bound_dev_if)
842 return -EINVAL;
843 }
844
Eric Dumazetefe42082013-10-03 15:42:29 -0700845 sk->sk_v6_daddr = usin->sin6_addr;
David S. Miller4c9483b2011-03-12 16:22:43 -0500846 np->flow_label = fl6.flowlabel;
Gerrit Renker73c9e022006-11-10 13:01:31 -0200847
848 /*
849 * DCCP over IPv4
850 */
851 if (addr_type == IPV6_ADDR_MAPPED) {
852 u32 exthdrlen = icsk->icsk_ext_hdr_len;
853 struct sockaddr_in sin;
854
855 SOCK_DEBUG(sk, "connect: ipv4 mapped\n");
856
857 if (__ipv6_only_sock(sk))
858 return -ENETUNREACH;
859
860 sin.sin_family = AF_INET;
861 sin.sin_port = usin->sin6_port;
862 sin.sin_addr.s_addr = usin->sin6_addr.s6_addr32[3];
863
864 icsk->icsk_af_ops = &dccp_ipv6_mapped;
865 sk->sk_backlog_rcv = dccp_v4_do_rcv;
866
867 err = dccp_v4_connect(sk, (struct sockaddr *)&sin, sizeof(sin));
868 if (err) {
869 icsk->icsk_ext_hdr_len = exthdrlen;
870 icsk->icsk_af_ops = &dccp_ipv6_af_ops;
871 sk->sk_backlog_rcv = dccp_v6_do_rcv;
872 goto failure;
Gerrit Renker73c9e022006-11-10 13:01:31 -0200873 }
Eric Dumazetd1e559d2015-03-18 14:05:35 -0700874 np->saddr = sk->sk_v6_rcv_saddr;
Gerrit Renker73c9e022006-11-10 13:01:31 -0200875 return err;
876 }
877
Eric Dumazetefe42082013-10-03 15:42:29 -0700878 if (!ipv6_addr_any(&sk->sk_v6_rcv_saddr))
879 saddr = &sk->sk_v6_rcv_saddr;
Gerrit Renker73c9e022006-11-10 13:01:31 -0200880
David S. Miller4c9483b2011-03-12 16:22:43 -0500881 fl6.flowi6_proto = IPPROTO_DCCP;
Eric Dumazetefe42082013-10-03 15:42:29 -0700882 fl6.daddr = sk->sk_v6_daddr;
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +0000883 fl6.saddr = saddr ? *saddr : np->saddr;
David S. Miller4c9483b2011-03-12 16:22:43 -0500884 fl6.flowi6_oif = sk->sk_bound_dev_if;
David S. Miller1958b852011-03-12 16:36:19 -0500885 fl6.fl6_dport = usin->sin6_port;
886 fl6.fl6_sport = inet->inet_sport;
David S. Miller4c9483b2011-03-12 16:22:43 -0500887 security_sk_classify_flow(sk, flowi6_to_flowi(&fl6));
Gerrit Renker73c9e022006-11-10 13:01:31 -0200888
Hannes Frederic Sowa1e1d04e2016-04-05 17:10:15 +0200889 opt = rcu_dereference_protected(np->opt, lockdep_sock_is_held(sk));
Eric Dumazet45f6fad2015-11-29 19:37:57 -0800890 final_p = fl6_update_dst(&fl6, opt, &final);
Gerrit Renker73c9e022006-11-10 13:01:31 -0200891
Steffen Klassert0e0d44a2013-08-28 08:04:14 +0200892 dst = ip6_dst_lookup_flow(sk, &fl6, final_p);
David S. Miller68d0c6d2011-03-01 13:19:07 -0800893 if (IS_ERR(dst)) {
894 err = PTR_ERR(dst);
Gerrit Renker73c9e022006-11-10 13:01:31 -0200895 goto failure;
David S. Miller14e50e52007-05-24 18:17:54 -0700896 }
Gerrit Renker73c9e022006-11-10 13:01:31 -0200897
898 if (saddr == NULL) {
David S. Miller4c9483b2011-03-12 16:22:43 -0500899 saddr = &fl6.saddr;
Eric Dumazetefe42082013-10-03 15:42:29 -0700900 sk->sk_v6_rcv_saddr = *saddr;
Gerrit Renker73c9e022006-11-10 13:01:31 -0200901 }
902
903 /* set the source address */
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +0000904 np->saddr = *saddr;
Eric Dumazetc720c7e2009-10-15 06:30:45 +0000905 inet->inet_rcv_saddr = LOOPBACK4_IPV6;
Gerrit Renker73c9e022006-11-10 13:01:31 -0200906
Eric Dumazet6bd4f352015-12-02 21:53:57 -0800907 ip6_dst_store(sk, dst, NULL, NULL);
Gerrit Renker73c9e022006-11-10 13:01:31 -0200908
909 icsk->icsk_ext_hdr_len = 0;
Eric Dumazet45f6fad2015-11-29 19:37:57 -0800910 if (opt)
911 icsk->icsk_ext_hdr_len = opt->opt_flen + opt->opt_nflen;
Gerrit Renker73c9e022006-11-10 13:01:31 -0200912
Eric Dumazetc720c7e2009-10-15 06:30:45 +0000913 inet->inet_dport = usin->sin6_port;
Gerrit Renker73c9e022006-11-10 13:01:31 -0200914
915 dccp_set_state(sk, DCCP_REQUESTING);
916 err = inet6_hash_connect(&dccp_death_row, sk);
917 if (err)
918 goto late_failure;
Gerrit Renkerd7f73652006-11-13 13:34:38 -0200919
920 dp->dccps_iss = secure_dccpv6_sequence_number(np->saddr.s6_addr32,
Eric Dumazetefe42082013-10-03 15:42:29 -0700921 sk->sk_v6_daddr.s6_addr32,
Eric Dumazetc720c7e2009-10-15 06:30:45 +0000922 inet->inet_sport,
923 inet->inet_dport);
Gerrit Renker73c9e022006-11-10 13:01:31 -0200924 err = dccp_connect(sk);
925 if (err)
926 goto late_failure;
927
928 return 0;
929
930late_failure:
931 dccp_set_state(sk, DCCP_CLOSED);
932 __sk_dst_reset(sk);
933failure:
Eric Dumazetc720c7e2009-10-15 06:30:45 +0000934 inet->inet_dport = 0;
Gerrit Renker73c9e022006-11-10 13:01:31 -0200935 sk->sk_route_caps = 0;
936 return err;
937}
938
Stephen Hemminger3b401a82009-09-01 19:25:04 +0000939static const struct inet_connection_sock_af_ops dccp_ipv6_af_ops = {
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -0800940 .queue_xmit = inet6_csk_xmit,
941 .send_check = dccp_v6_send_check,
942 .rebuild_header = inet6_sk_rebuild_header,
943 .conn_request = dccp_v6_conn_request,
944 .syn_recv_sock = dccp_v6_request_recv_sock,
945 .net_header_len = sizeof(struct ipv6hdr),
946 .setsockopt = ipv6_setsockopt,
947 .getsockopt = ipv6_getsockopt,
948 .addr2sockaddr = inet6_csk_addr2sockaddr,
949 .sockaddr_len = sizeof(struct sockaddr_in6),
Arnaldo Carvalho de Meloab1e0a12008-02-03 04:06:04 -0800950 .bind_conflict = inet6_csk_bind_conflict,
Dmitry Mishin3fdadf72006-03-20 22:45:21 -0800951#ifdef CONFIG_COMPAT
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -0800952 .compat_setsockopt = compat_ipv6_setsockopt,
953 .compat_getsockopt = compat_ipv6_getsockopt,
Dmitry Mishin3fdadf72006-03-20 22:45:21 -0800954#endif
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800955};
956
957/*
958 * DCCP over IPv4 via INET6 API
959 */
Stephen Hemminger3b401a82009-09-01 19:25:04 +0000960static const struct inet_connection_sock_af_ops dccp_ipv6_mapped = {
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -0800961 .queue_xmit = ip_queue_xmit,
962 .send_check = dccp_v4_send_check,
963 .rebuild_header = inet_sk_rebuild_header,
964 .conn_request = dccp_v6_conn_request,
965 .syn_recv_sock = dccp_v6_request_recv_sock,
966 .net_header_len = sizeof(struct iphdr),
967 .setsockopt = ipv6_setsockopt,
968 .getsockopt = ipv6_getsockopt,
969 .addr2sockaddr = inet6_csk_addr2sockaddr,
970 .sockaddr_len = sizeof(struct sockaddr_in6),
Eric Dumazet990ff4d2016-11-03 08:59:46 -0700971 .bind_conflict = inet6_csk_bind_conflict,
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/* NOTE: A lot of things set to zero explicitly by call to
979 * sk_alloc() so need not be done here.
980 */
981static int dccp_v6_init_sock(struct sock *sk)
982{
Arnaldo Carvalho de Melo72478872006-03-20 22:00:37 -0800983 static __u8 dccp_v6_ctl_sock_initialized;
984 int err = dccp_init_sock(sk, dccp_v6_ctl_sock_initialized);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800985
Arnaldo Carvalho de Melo72478872006-03-20 22:00:37 -0800986 if (err == 0) {
987 if (unlikely(!dccp_v6_ctl_sock_initialized))
988 dccp_v6_ctl_sock_initialized = 1;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800989 inet_csk(sk)->icsk_af_ops = &dccp_ipv6_af_ops;
Arnaldo Carvalho de Melo72478872006-03-20 22:00:37 -0800990 }
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800991
992 return err;
993}
994
Brian Haley7d06b2e2008-06-14 17:04:49 -0700995static void dccp_v6_destroy_sock(struct sock *sk)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800996{
Arnaldo Carvalho de Melo3e0fadc2006-03-20 21:23:15 -0800997 dccp_destroy_sock(sk);
Brian Haley7d06b2e2008-06-14 17:04:49 -0700998 inet6_destroy_sock(sk);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800999}
1000
Gerrit Renker73c9e022006-11-10 13:01:31 -02001001static struct timewait_sock_ops dccp6_timewait_sock_ops = {
1002 .twsk_obj_size = sizeof(struct dccp6_timewait_sock),
1003};
1004
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001005static struct proto dccp_v6_prot = {
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001006 .name = "DCCPv6",
1007 .owner = THIS_MODULE,
1008 .close = dccp_close,
1009 .connect = dccp_v6_connect,
1010 .disconnect = dccp_disconnect,
1011 .ioctl = dccp_ioctl,
1012 .init = dccp_v6_init_sock,
1013 .setsockopt = dccp_setsockopt,
1014 .getsockopt = dccp_getsockopt,
1015 .sendmsg = dccp_sendmsg,
1016 .recvmsg = dccp_recvmsg,
1017 .backlog_rcv = dccp_v6_do_rcv,
Craig Gallek496611d2016-02-10 11:50:36 -05001018 .hash = inet6_hash,
Arnaldo Carvalho de Meloab1e0a12008-02-03 04:06:04 -08001019 .unhash = inet_unhash,
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001020 .accept = inet_csk_accept,
Arnaldo Carvalho de Meloab1e0a12008-02-03 04:06:04 -08001021 .get_port = inet_csk_get_port,
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001022 .shutdown = dccp_shutdown,
1023 .destroy = dccp_v6_destroy_sock,
1024 .orphan_count = &dccp_orphan_count,
1025 .max_header = MAX_DCCP_HEADER,
1026 .obj_size = sizeof(struct dccp6_sock),
Eric Dumazet3ab5aee2008-11-16 19:40:17 -08001027 .slab_flags = SLAB_DESTROY_BY_RCU,
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001028 .rsk_prot = &dccp6_request_sock_ops,
1029 .twsk_prot = &dccp6_timewait_sock_ops,
Pavel Emelyanov39d8cda2008-03-22 16:50:58 -07001030 .h.hashinfo = &dccp_hashinfo,
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001031#ifdef CONFIG_COMPAT
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001032 .compat_setsockopt = compat_dccp_setsockopt,
1033 .compat_getsockopt = compat_dccp_getsockopt,
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001034#endif
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001035};
1036
Alexey Dobriyan41135cc2009-09-14 12:22:28 +00001037static const struct inet6_protocol dccp_v6_protocol = {
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -08001038 .handler = dccp_v6_rcv,
1039 .err_handler = dccp_v6_err,
1040 .flags = INET6_PROTO_NOPOLICY | INET6_PROTO_FINAL,
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001041};
1042
Alexey Dobriyan5708e862009-09-14 12:23:23 +00001043static const struct proto_ops inet6_dccp_ops = {
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001044 .family = PF_INET6,
1045 .owner = THIS_MODULE,
1046 .release = inet6_release,
1047 .bind = inet6_bind,
1048 .connect = inet_stream_connect,
1049 .socketpair = sock_no_socketpair,
1050 .accept = inet_accept,
1051 .getname = inet6_getname,
1052 .poll = dccp_poll,
1053 .ioctl = inet6_ioctl,
1054 .listen = inet_dccp_listen,
1055 .shutdown = inet_shutdown,
1056 .setsockopt = sock_common_setsockopt,
1057 .getsockopt = sock_common_getsockopt,
1058 .sendmsg = inet_sendmsg,
1059 .recvmsg = sock_common_recvmsg,
1060 .mmap = sock_no_mmap,
1061 .sendpage = sock_no_sendpage,
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001062#ifdef CONFIG_COMPAT
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001063 .compat_setsockopt = compat_sock_common_setsockopt,
1064 .compat_getsockopt = compat_sock_common_getsockopt,
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001065#endif
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001066};
1067
1068static struct inet_protosw dccp_v6_protosw = {
1069 .type = SOCK_DCCP,
1070 .protocol = IPPROTO_DCCP,
1071 .prot = &dccp_v6_prot,
1072 .ops = &inet6_dccp_ops,
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -08001073 .flags = INET_PROTOSW_ICSK,
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001074};
1075
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00001076static int __net_init dccp_v6_init_net(struct net *net)
Pavel Emelyanov8231bd22008-04-13 22:32:02 -07001077{
Gerrit Renkerd14a0eb2010-03-14 20:13:19 +00001078 if (dccp_hashinfo.bhash == NULL)
1079 return -ESOCKTNOSUPPORT;
Pavel Emelyanov334527d2008-04-13 22:32:45 -07001080
Gerrit Renkerd14a0eb2010-03-14 20:13:19 +00001081 return inet_ctl_sock_create(&net->dccp.v6_ctl_sk, PF_INET6,
1082 SOCK_DCCP, IPPROTO_DCCP, net);
Pavel Emelyanov8231bd22008-04-13 22:32:02 -07001083}
1084
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00001085static void __net_exit dccp_v6_exit_net(struct net *net)
Pavel Emelyanov8231bd22008-04-13 22:32:02 -07001086{
Pavel Emelyanov334527d2008-04-13 22:32:45 -07001087 inet_ctl_sock_destroy(net->dccp.v6_ctl_sk);
Pavel Emelyanov8231bd22008-04-13 22:32:02 -07001088}
1089
1090static struct pernet_operations dccp_v6_ops = {
1091 .init = dccp_v6_init_net,
1092 .exit = dccp_v6_exit_net,
1093};
1094
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001095static int __init dccp_v6_init(void)
1096{
1097 int err = proto_register(&dccp_v6_prot, 1);
1098
1099 if (err != 0)
1100 goto out;
1101
1102 err = inet6_add_protocol(&dccp_v6_protocol, IPPROTO_DCCP);
1103 if (err != 0)
1104 goto out_unregister_proto;
1105
1106 inet6_register_protosw(&dccp_v6_protosw);
Arnaldo Carvalho de Melo72478872006-03-20 22:00:37 -08001107
Pavel Emelyanov8231bd22008-04-13 22:32:02 -07001108 err = register_pernet_subsys(&dccp_v6_ops);
1109 if (err != 0)
1110 goto out_destroy_ctl_sock;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001111out:
1112 return err;
Pavel Emelyanov8231bd22008-04-13 22:32:02 -07001113
1114out_destroy_ctl_sock:
Arnaldo Carvalho de Melo72478872006-03-20 22:00:37 -08001115 inet6_del_protocol(&dccp_v6_protocol, IPPROTO_DCCP);
1116 inet6_unregister_protosw(&dccp_v6_protosw);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001117out_unregister_proto:
1118 proto_unregister(&dccp_v6_prot);
1119 goto out;
1120}
1121
1122static void __exit dccp_v6_exit(void)
1123{
Pavel Emelyanov8231bd22008-04-13 22:32:02 -07001124 unregister_pernet_subsys(&dccp_v6_ops);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001125 inet6_del_protocol(&dccp_v6_protocol, IPPROTO_DCCP);
1126 inet6_unregister_protosw(&dccp_v6_protosw);
1127 proto_unregister(&dccp_v6_prot);
1128}
1129
1130module_init(dccp_v6_init);
1131module_exit(dccp_v6_exit);
1132
1133/*
1134 * __stringify doesn't likes enums, so use SOCK_DCCP (6) and IPPROTO_DCCP (33)
1135 * values directly, Also cover the case where the protocol is not specified,
1136 * i.e. net-pf-PF_INET6-proto-0-type-SOCK_DCCP
1137 */
Jean Delvare7131c6c2007-10-21 16:45:03 -07001138MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_INET6, 33, 6);
1139MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_INET6, 0, 6);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001140MODULE_LICENSE("GPL");
1141MODULE_AUTHOR("Arnaldo Carvalho de Melo <acme@mandriva.com>");
1142MODULE_DESCRIPTION("DCCPv6 - Datagram Congestion Controlled Protocol");