blob: 93e7a1fe73d6a99e9fcf9945fff91aef02f1ee58 [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
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -080043static void dccp_v6_hash(struct sock *sk)
44{
45 if (sk->sk_state != DCCP_CLOSED) {
46 if (inet_csk(sk)->icsk_af_ops == &dccp_ipv6_mapped) {
Arnaldo Carvalho de Meloab1e0a12008-02-03 04:06:04 -080047 inet_hash(sk);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -080048 return;
49 }
50 local_bh_disable();
Eric Dumazet9327f702009-12-04 03:46:54 +000051 __inet6_hash(sk, NULL);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -080052 local_bh_enable();
53 }
54}
55
Gerrit Renker6f4e5ff2006-11-10 17:43:06 -020056/* add pseudo-header to DCCP checksum stored in skb->csum */
Al Viro868c86b2006-11-14 21:35:48 -080057static inline __sum16 dccp_v6_csum_finish(struct sk_buff *skb,
Eric Dumazetb71d1d42011-04-22 04:53:02 +000058 const struct in6_addr *saddr,
59 const struct in6_addr *daddr)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -080060{
Gerrit Renker6f4e5ff2006-11-10 17:43:06 -020061 return csum_ipv6_magic(saddr, daddr, skb->len, IPPROTO_DCCP, skb->csum);
62}
63
Herbert Xubb296242010-04-11 02:15:55 +000064static inline void dccp_v6_send_check(struct sock *sk, struct sk_buff *skb)
Gerrit Renker6f4e5ff2006-11-10 17:43:06 -020065{
66 struct ipv6_pinfo *np = inet6_sk(sk);
67 struct dccp_hdr *dh = dccp_hdr(skb);
68
69 dccp_csum_outgoing(skb);
70 dh->dccph_checksum = dccp_v6_csum_finish(skb, &np->saddr, &np->daddr);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -080071}
72
David S. Miller6e5714e2011-08-03 20:50:44 -070073static inline __u64 dccp_v6_init_sequence(struct sk_buff *skb)
Gerrit Renkerd7f73652006-11-13 13:34:38 -020074{
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -070075 return secure_dccpv6_sequence_number(ipv6_hdr(skb)->daddr.s6_addr32,
76 ipv6_hdr(skb)->saddr.s6_addr32,
Gerrit Renkerd7f73652006-11-13 13:34:38 -020077 dccp_hdr(skb)->dccph_dport,
78 dccp_hdr(skb)->dccph_sport );
79
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -080080}
81
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -080082static void dccp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
Brian Haleyd5fdd6b2009-06-23 04:31:07 -070083 u8 type, u8 code, int offset, __be32 info)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -080084{
Eric Dumazetb71d1d42011-04-22 04:53:02 +000085 const struct ipv6hdr *hdr = (const struct ipv6hdr *)skb->data;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -080086 const struct dccp_hdr *dh = (struct dccp_hdr *)(skb->data + offset);
Wei Yongjune0bcfb02008-07-26 11:59:10 +010087 struct dccp_sock *dp;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -080088 struct ipv6_pinfo *np;
89 struct sock *sk;
90 int err;
91 __u64 seq;
Pavel Emelyanovca12a1a2008-07-16 20:28:42 -070092 struct net *net = dev_net(skb->dev);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -080093
Wei Yongjun860239c2008-07-26 11:59:11 +010094 if (skb->len < offset + sizeof(*dh) ||
95 skb->len < offset + __dccp_basic_hdr_len(dh)) {
Denis V. Luneve41b5362008-10-08 10:33:26 -070096 ICMP6_INC_STATS_BH(net, __in6_dev_get(skb->dev),
97 ICMP6_MIB_INERRORS);
Wei Yongjun860239c2008-07-26 11:59:11 +010098 return;
99 }
100
Pavel Emelyanovca12a1a2008-07-16 20:28:42 -0700101 sk = inet6_lookup(net, &dccp_hashinfo,
Pavel Emelyanov671a1c72008-04-13 22:33:06 -0700102 &hdr->daddr, dh->dccph_dport,
Pavel Emelyanovd86e0da2008-01-31 05:07:21 -0800103 &hdr->saddr, dh->dccph_sport, inet6_iif(skb));
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800104
105 if (sk == NULL) {
Denis V. Luneve41b5362008-10-08 10:33:26 -0700106 ICMP6_INC_STATS_BH(net, __in6_dev_get(skb->dev),
107 ICMP6_MIB_INERRORS);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800108 return;
109 }
110
111 if (sk->sk_state == DCCP_TIME_WAIT) {
YOSHIFUJI Hideaki9469c7b2006-10-10 19:41:46 -0700112 inet_twsk_put(inet_twsk(sk));
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800113 return;
114 }
115
116 bh_lock_sock(sk);
117 if (sock_owned_by_user(sk))
Pavel Emelyanovde0744a2008-07-16 20:31:16 -0700118 NET_INC_STATS_BH(net, LINUX_MIB_LOCKDROPPEDICMPS);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800119
120 if (sk->sk_state == DCCP_CLOSED)
121 goto out;
122
Wei Yongjune0bcfb02008-07-26 11:59:10 +0100123 dp = dccp_sk(sk);
124 seq = dccp_hdr_seq(dh);
125 if ((1 << sk->sk_state) & ~(DCCPF_REQUESTING | DCCPF_LISTEN) &&
126 !between48(seq, dp->dccps_awl, dp->dccps_awh)) {
127 NET_INC_STATS_BH(net, LINUX_MIB_OUTOFWINDOWICMPS);
128 goto out;
129 }
130
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800131 np = inet6_sk(sk);
132
133 if (type == ICMPV6_PKT_TOOBIG) {
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800134 struct dst_entry *dst = NULL;
135
136 if (sock_owned_by_user(sk))
137 goto out;
138 if ((1 << sk->sk_state) & (DCCPF_LISTEN | DCCPF_CLOSED))
139 goto out;
140
141 /* icmp should have updated the destination cache entry */
142 dst = __sk_dst_check(sk, np->dst_cookie);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800143 if (dst == NULL) {
144 struct inet_sock *inet = inet_sk(sk);
David S. Miller4c9483b2011-03-12 16:22:43 -0500145 struct flowi6 fl6;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800146
147 /* BUGGG_FUTURE: Again, it is not clear how
148 to handle rthdr case. Ignore this complexity
149 for now.
150 */
David S. Miller4c9483b2011-03-12 16:22:43 -0500151 memset(&fl6, 0, sizeof(fl6));
152 fl6.flowi6_proto = IPPROTO_DCCP;
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +0000153 fl6.daddr = np->daddr;
154 fl6.saddr = np->saddr;
David S. Miller4c9483b2011-03-12 16:22:43 -0500155 fl6.flowi6_oif = sk->sk_bound_dev_if;
David S. Miller1958b852011-03-12 16:36:19 -0500156 fl6.fl6_dport = inet->inet_dport;
157 fl6.fl6_sport = inet->inet_sport;
David S. Miller4c9483b2011-03-12 16:22:43 -0500158 security_sk_classify_flow(sk, flowi6_to_flowi(&fl6));
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800159
David S. Miller4c9483b2011-03-12 16:22:43 -0500160 dst = ip6_dst_lookup_flow(sk, &fl6, NULL, false);
David S. Miller68d0c6d2011-03-01 13:19:07 -0800161 if (IS_ERR(dst)) {
162 sk->sk_err_soft = -PTR_ERR(dst);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800163 goto out;
164 }
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800165 } else
166 dst_hold(dst);
167
David S. Millere2939ea2012-06-15 14:54:11 -0700168 dst->ops->update_pmtu(dst, ntohl(info));
169
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -0800170 if (inet_csk(sk)->icsk_pmtu_cookie > dst_mtu(dst)) {
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800171 dccp_sync_mss(sk, dst_mtu(dst));
172 } /* else let the usual retransmit timer handle it */
173 dst_release(dst);
174 goto out;
175 }
176
177 icmpv6_err_convert(type, code, &err);
178
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800179 /* Might be for an request_sock */
180 switch (sk->sk_state) {
181 struct request_sock *req, **prev;
182 case DCCP_LISTEN:
183 if (sock_owned_by_user(sk))
184 goto out;
185
186 req = inet6_csk_search_req(sk, &prev, dh->dccph_dport,
187 &hdr->daddr, &hdr->saddr,
188 inet6_iif(skb));
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800189 if (req == NULL)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800190 goto out;
191
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800192 /*
193 * ICMPs are not backlogged, hence we cannot get an established
194 * socket here.
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800195 */
Ilpo Järvinen547b7922008-07-25 21:43:18 -0700196 WARN_ON(req->sk != NULL);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800197
Samuel Jerof541fb72012-02-26 18:22:02 -0700198 if (!between48(seq, dccp_rsk(req)->dreq_iss,
199 dccp_rsk(req)->dreq_gss)) {
Pavel Emelyanovde0744a2008-07-16 20:31:16 -0700200 NET_INC_STATS_BH(net, LINUX_MIB_OUTOFWINDOWICMPS);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800201 goto out;
202 }
203
204 inet_csk_reqsk_queue_drop(sk, req, prev);
205 goto out;
206
207 case DCCP_REQUESTING:
208 case DCCP_RESPOND: /* Cannot happen.
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800209 It can, it SYNs are crossed. --ANK */
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800210 if (!sock_owned_by_user(sk)) {
211 DCCP_INC_STATS_BH(DCCP_MIB_ATTEMPTFAILS);
212 sk->sk_err = err;
213 /*
214 * Wake people up to see the error
215 * (see connect in sock.c)
216 */
217 sk->sk_error_report(sk);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800218 dccp_done(sk);
219 } else
220 sk->sk_err_soft = err;
221 goto out;
222 }
223
224 if (!sock_owned_by_user(sk) && np->recverr) {
225 sk->sk_err = err;
226 sk->sk_error_report(sk);
227 } else
228 sk->sk_err_soft = err;
229
230out:
231 bh_unlock_sock(sk);
232 sock_put(sk);
233}
234
235
William Allen Simpsone6b4d112009-12-02 18:07:39 +0000236static int dccp_v6_send_response(struct sock *sk, struct request_sock *req,
237 struct request_values *rv_unused)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800238{
239 struct inet6_request_sock *ireq6 = inet6_rsk(req);
240 struct ipv6_pinfo *np = inet6_sk(sk);
241 struct sk_buff *skb;
242 struct ipv6_txoptions *opt = NULL;
Arnaud Ebalard20c59de2010-06-01 21:35:01 +0000243 struct in6_addr *final_p, final;
David S. Miller4c9483b2011-03-12 16:22:43 -0500244 struct flowi6 fl6;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800245 int err = -1;
Denis V. Lunevfd80eb92008-02-29 11:43:03 -0800246 struct dst_entry *dst;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800247
David S. Miller4c9483b2011-03-12 16:22:43 -0500248 memset(&fl6, 0, sizeof(fl6));
249 fl6.flowi6_proto = IPPROTO_DCCP;
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +0000250 fl6.daddr = ireq6->rmt_addr;
251 fl6.saddr = ireq6->loc_addr;
David S. Miller4c9483b2011-03-12 16:22:43 -0500252 fl6.flowlabel = 0;
253 fl6.flowi6_oif = ireq6->iif;
David S. Miller1958b852011-03-12 16:36:19 -0500254 fl6.fl6_dport = inet_rsk(req)->rmt_port;
255 fl6.fl6_sport = inet_rsk(req)->loc_port;
David S. Miller4c9483b2011-03-12 16:22:43 -0500256 security_req_classify_flow(req, flowi6_to_flowi(&fl6));
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800257
Eric Dumazeta432b342015-11-29 19:37:57 -0800258 rcu_read_lock();
259 final_p = fl6_update_dst(&fl6, rcu_dereference(np->opt), &final);
260 rcu_read_unlock();
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800261
David S. Miller4c9483b2011-03-12 16:22:43 -0500262 dst = ip6_dst_lookup_flow(sk, &fl6, final_p, false);
David S. Miller68d0c6d2011-03-01 13:19:07 -0800263 if (IS_ERR(dst)) {
264 err = PTR_ERR(dst);
265 dst = NULL;
Denis V. Lunevfd80eb92008-02-29 11:43:03 -0800266 goto done;
David S. Miller68d0c6d2011-03-01 13:19:07 -0800267 }
Denis V. Lunevfd80eb92008-02-29 11:43:03 -0800268
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800269 skb = dccp_make_response(sk, dst, req);
270 if (skb != NULL) {
271 struct dccp_hdr *dh = dccp_hdr(skb);
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800272
Gerrit Renker6f4e5ff2006-11-10 17:43:06 -0200273 dh->dccph_checksum = dccp_v6_csum_finish(skb,
274 &ireq6->loc_addr,
275 &ireq6->rmt_addr);
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +0000276 fl6.daddr = ireq6->rmt_addr;
Eric Dumazeta432b342015-11-29 19:37:57 -0800277 rcu_read_lock();
278 err = ip6_xmit(sk, skb, &fl6, rcu_dereference(np->opt),
279 np->tclass);
280 rcu_read_unlock();
Gerrit Renkerb9df3cb2006-11-14 11:21:36 -0200281 err = net_xmit_eval(err);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800282 }
283
284done:
David S. Miller0cbd7822006-01-31 17:53:37 -0800285 dst_release(dst);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800286 return err;
287}
288
289static void dccp_v6_reqsk_destructor(struct request_sock *req)
290{
Gerrit Renkerd99a7bd2008-11-04 23:56:30 -0800291 dccp_feat_list_purge(&dccp_rsk(req)->dreq_featneg);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800292 if (inet6_rsk(req)->pktopts != NULL)
293 kfree_skb(inet6_rsk(req)->pktopts);
294}
295
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800296static void dccp_v6_ctl_send_reset(struct sock *sk, struct sk_buff *rxskb)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800297{
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000298 const struct ipv6hdr *rxip6h;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800299 struct sk_buff *skb;
David S. Miller4c9483b2011-03-12 16:22:43 -0500300 struct flowi6 fl6;
Eric Dumazetadf30902009-06-02 05:19:30 +0000301 struct net *net = dev_net(skb_dst(rxskb)->dev);
Pavel Emelyanov334527d2008-04-13 22:32:45 -0700302 struct sock *ctl_sk = net->dccp.v6_ctl_sk;
Eric Dumazetadf30902009-06-02 05:19:30 +0000303 struct dst_entry *dst;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800304
Gerrit Renkere356d372007-09-26 14:35:19 -0300305 if (dccp_hdr(rxskb)->dccph_type == DCCP_PKT_RESET)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800306 return;
307
308 if (!ipv6_unicast_destination(rxskb))
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800309 return;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800310
Pavel Emelyanov02047742008-04-13 22:32:25 -0700311 skb = dccp_ctl_make_reset(ctl_sk, rxskb);
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800312 if (skb == NULL)
Arnaldo Carvalho de Melo8109b022006-12-10 16:01:18 -0200313 return;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800314
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700315 rxip6h = ipv6_hdr(rxskb);
Gerrit Renkere356d372007-09-26 14:35:19 -0300316 dccp_hdr(skb)->dccph_checksum = dccp_v6_csum_finish(skb, &rxip6h->saddr,
317 &rxip6h->daddr);
Gerrit Renker6f4e5ff2006-11-10 17:43:06 -0200318
David S. Miller4c9483b2011-03-12 16:22:43 -0500319 memset(&fl6, 0, sizeof(fl6));
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +0000320 fl6.daddr = rxip6h->saddr;
321 fl6.saddr = rxip6h->daddr;
Gerrit Renker6f4e5ff2006-11-10 17:43:06 -0200322
David S. Miller4c9483b2011-03-12 16:22:43 -0500323 fl6.flowi6_proto = IPPROTO_DCCP;
324 fl6.flowi6_oif = inet6_iif(rxskb);
David S. Miller1958b852011-03-12 16:36:19 -0500325 fl6.fl6_dport = dccp_hdr(skb)->dccph_dport;
326 fl6.fl6_sport = dccp_hdr(skb)->dccph_sport;
David S. Miller4c9483b2011-03-12 16:22:43 -0500327 security_skb_classify_flow(rxskb, flowi6_to_flowi(&fl6));
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800328
329 /* sk = NULL, but it is safe for now. RST socket required. */
David S. Miller4c9483b2011-03-12 16:22:43 -0500330 dst = ip6_dst_lookup_flow(ctl_sk, &fl6, NULL, false);
David S. Miller68d0c6d2011-03-01 13:19:07 -0800331 if (!IS_ERR(dst)) {
332 skb_dst_set(skb, dst);
Eric Dumazetb903d322011-10-27 00:44:35 -0400333 ip6_xmit(ctl_sk, skb, &fl6, NULL, 0);
David S. Miller68d0c6d2011-03-01 13:19:07 -0800334 DCCP_INC_STATS_BH(DCCP_MIB_OUTSEGS);
335 DCCP_INC_STATS_BH(DCCP_MIB_OUTRSTS);
336 return;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800337 }
338
339 kfree_skb(skb);
340}
341
Gerrit Renker73c9e022006-11-10 13:01:31 -0200342static struct request_sock_ops dccp6_request_sock_ops = {
343 .family = AF_INET6,
344 .obj_size = sizeof(struct dccp6_request_sock),
345 .rtx_syn_ack = dccp_v6_send_response,
346 .send_ack = dccp_reqsk_send_ack,
347 .destructor = dccp_v6_reqsk_destructor,
348 .send_reset = dccp_v6_ctl_send_reset,
349};
350
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800351static struct sock *dccp_v6_hnd_req(struct sock *sk,struct sk_buff *skb)
352{
353 const struct dccp_hdr *dh = dccp_hdr(skb);
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700354 const struct ipv6hdr *iph = ipv6_hdr(skb);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800355 struct sock *nsk;
356 struct request_sock **prev;
357 /* Find possible connection requests. */
358 struct request_sock *req = inet6_csk_search_req(sk, &prev,
359 dh->dccph_sport,
360 &iph->saddr,
361 &iph->daddr,
362 inet6_iif(skb));
363 if (req != NULL)
364 return dccp_check_req(sk, skb, req, prev);
365
Pavel Emelyanov671a1c72008-04-13 22:33:06 -0700366 nsk = __inet6_lookup_established(sock_net(sk), &dccp_hashinfo,
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800367 &iph->saddr, dh->dccph_sport,
368 &iph->daddr, ntohs(dh->dccph_dport),
369 inet6_iif(skb));
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800370 if (nsk != NULL) {
371 if (nsk->sk_state != DCCP_TIME_WAIT) {
372 bh_lock_sock(nsk);
373 return nsk;
374 }
YOSHIFUJI Hideaki9469c7b2006-10-10 19:41:46 -0700375 inet_twsk_put(inet_twsk(nsk));
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800376 return NULL;
377 }
378
379 return sk;
380}
381
382static int dccp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
383{
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800384 struct request_sock *req;
385 struct dccp_request_sock *dreq;
386 struct inet6_request_sock *ireq6;
387 struct ipv6_pinfo *np = inet6_sk(sk);
Arnaldo Carvalho de Melo8109b022006-12-10 16:01:18 -0200388 const __be32 service = dccp_hdr_request(skb)->dccph_req_service;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800389 struct dccp_skb_cb *dcb = DCCP_SKB_CB(skb);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800390
391 if (skb->protocol == htons(ETH_P_IP))
392 return dccp_v4_conn_request(sk, skb);
393
394 if (!ipv6_unicast_destination(skb))
Gerrit Renker4a5409a2007-10-04 14:52:28 -0700395 return 0; /* discard, don't send a reset here */
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800396
397 if (dccp_bad_service_code(sk, service)) {
Gerrit Renker4a5409a2007-10-04 14:52:28 -0700398 dcb->dccpd_reset_code = DCCP_RESET_CODE_BAD_SERVICE_CODE;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800399 goto drop;
Arnaldo Carvalho de Melo8109b022006-12-10 16:01:18 -0200400 }
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800401 /*
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800402 * There are no SYN attacks on IPv6, yet...
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800403 */
Gerrit Renker4a5409a2007-10-04 14:52:28 -0700404 dcb->dccpd_reset_code = DCCP_RESET_CODE_TOO_BUSY;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800405 if (inet_csk_reqsk_queue_is_full(sk))
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800406 goto drop;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800407
408 if (sk_acceptq_is_full(sk) && inet_csk_reqsk_queue_young(sk) > 1)
409 goto drop;
410
Gerrit Renker82709532006-10-11 16:26:54 +0100411 req = inet6_reqsk_alloc(&dccp6_request_sock_ops);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800412 if (req == NULL)
413 goto drop;
414
Gerrit Renkerac757732008-11-04 23:55:49 -0800415 if (dccp_reqsk_init(req, dccp_sk(sk), skb))
416 goto drop_and_free;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800417
Gerrit Renker8b819412007-12-13 12:29:24 -0200418 dreq = dccp_rsk(req);
419 if (dccp_parse_options(sk, dreq, skb))
420 goto drop_and_free;
421
Venkat Yekkirala4237c752006-07-24 23:32:50 -0700422 if (security_inet_conn_request(sk, skb, req))
423 goto drop_and_free;
424
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800425 ireq6 = inet6_rsk(req);
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +0000426 ireq6->rmt_addr = ipv6_hdr(skb)->saddr;
427 ireq6->loc_addr = ipv6_hdr(skb)->daddr;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800428
429 if (ipv6_opt_accepted(sk, skb) ||
430 np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo ||
431 np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim) {
432 atomic_inc(&skb->users);
433 ireq6->pktopts = skb;
434 }
435 ireq6->iif = sk->sk_bound_dev_if;
436
437 /* So that link locals have meaning */
438 if (!sk->sk_bound_dev_if &&
439 ipv6_addr_type(&ireq6->rmt_addr) & IPV6_ADDR_LINKLOCAL)
440 ireq6->iif = inet6_iif(skb);
441
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800442 /*
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800443 * Step 3: Process LISTEN state
444 *
Gerrit Renkerd83ca5a2006-11-10 16:29:14 -0200445 * Set S.ISR, S.GSR, S.SWL, S.SWH from packet or Init Cookie
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800446 *
Samuel Jerof541fb72012-02-26 18:22:02 -0700447 * Setting S.SWL/S.SWH to is deferred to dccp_create_openreq_child().
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800448 */
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800449 dreq->dreq_isr = dcb->dccpd_seq;
Samuel Jerof541fb72012-02-26 18:22:02 -0700450 dreq->dreq_gsr = dreq->dreq_isr;
Gerrit Renker865e9022006-11-13 13:31:50 -0200451 dreq->dreq_iss = dccp_v6_init_sequence(skb);
Samuel Jerof541fb72012-02-26 18:22:02 -0700452 dreq->dreq_gss = dreq->dreq_iss;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800453 dreq->dreq_service = service;
454
William Allen Simpsone6b4d112009-12-02 18:07:39 +0000455 if (dccp_v6_send_response(sk, req, NULL))
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800456 goto drop_and_free;
457
458 inet6_csk_reqsk_queue_hash_add(sk, req, DCCP_TIMEOUT_INIT);
459 return 0;
460
461drop_and_free:
462 reqsk_free(req);
463drop:
464 DCCP_INC_STATS_BH(DCCP_MIB_ATTEMPTFAILS);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800465 return -1;
466}
467
468static struct sock *dccp_v6_request_recv_sock(struct sock *sk,
469 struct sk_buff *skb,
470 struct request_sock *req,
471 struct dst_entry *dst)
472{
473 struct inet6_request_sock *ireq6 = inet6_rsk(req);
474 struct ipv6_pinfo *newnp, *np = inet6_sk(sk);
Eric Dumazeta432b342015-11-29 19:37:57 -0800475 struct ipv6_txoptions *opt;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800476 struct inet_sock *newinet;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800477 struct dccp6_sock *newdp6;
478 struct sock *newsk;
479 struct ipv6_txoptions *opt;
480
481 if (skb->protocol == htons(ETH_P_IP)) {
482 /*
483 * v6 mapped
484 */
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800485 newsk = dccp_v4_request_recv_sock(sk, skb, req, dst);
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800486 if (newsk == NULL)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800487 return NULL;
488
489 newdp6 = (struct dccp6_sock *)newsk;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800490 newinet = inet_sk(newsk);
491 newinet->pinet6 = &newdp6->inet6;
492 newnp = inet6_sk(newsk);
493
494 memcpy(newnp, np, sizeof(struct ipv6_pinfo));
495
Eric Dumazetc720c7e2009-10-15 06:30:45 +0000496 ipv6_addr_set_v4mapped(newinet->inet_daddr, &newnp->daddr);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800497
Eric Dumazetc720c7e2009-10-15 06:30:45 +0000498 ipv6_addr_set_v4mapped(newinet->inet_saddr, &newnp->saddr);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800499
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +0000500 newnp->rcv_saddr = newnp->saddr;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800501
502 inet_csk(newsk)->icsk_af_ops = &dccp_ipv6_mapped;
503 newsk->sk_backlog_rcv = dccp_v4_do_rcv;
504 newnp->pktoptions = NULL;
505 newnp->opt = NULL;
WANG Cong63572be2017-08-16 16:04:14 +0800506 newnp->ipv6_mc_list = NULL;
507 newnp->ipv6_ac_list = NULL;
508 newnp->ipv6_fl_list = NULL;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800509 newnp->mcast_oif = inet6_iif(skb);
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700510 newnp->mcast_hops = ipv6_hdr(skb)->hop_limit;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800511
512 /*
513 * No need to charge this sock to the relevant IPv6 refcnt debug socks count
514 * here, dccp_create_openreq_child now does this for us, see the comment in
515 * that function for the gory details. -acme
516 */
517
518 /* It is tricky place. Until this moment IPv4 tcp
519 worked with IPv6 icsk.icsk_af_ops.
520 Sync it now.
521 */
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -0800522 dccp_sync_mss(newsk, inet_csk(newsk)->icsk_pmtu_cookie);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800523
524 return newsk;
525 }
526
527 opt = np->opt;
528
529 if (sk_acceptq_is_full(sk))
530 goto out_overflow;
531
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800532 if (dst == NULL) {
Arnaud Ebalard20c59de2010-06-01 21:35:01 +0000533 struct in6_addr *final_p, final;
David S. Miller4c9483b2011-03-12 16:22:43 -0500534 struct flowi6 fl6;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800535
David S. Miller4c9483b2011-03-12 16:22:43 -0500536 memset(&fl6, 0, sizeof(fl6));
537 fl6.flowi6_proto = IPPROTO_DCCP;
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +0000538 fl6.daddr = ireq6->rmt_addr;
David S. Miller4c9483b2011-03-12 16:22:43 -0500539 final_p = fl6_update_dst(&fl6, opt, &final);
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +0000540 fl6.saddr = ireq6->loc_addr;
David S. Miller4c9483b2011-03-12 16:22:43 -0500541 fl6.flowi6_oif = sk->sk_bound_dev_if;
David S. Miller1958b852011-03-12 16:36:19 -0500542 fl6.fl6_dport = inet_rsk(req)->rmt_port;
543 fl6.fl6_sport = inet_rsk(req)->loc_port;
David S. Miller4c9483b2011-03-12 16:22:43 -0500544 security_sk_classify_flow(sk, flowi6_to_flowi(&fl6));
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800545
David S. Miller4c9483b2011-03-12 16:22:43 -0500546 dst = ip6_dst_lookup_flow(sk, &fl6, final_p, false);
David S. Miller68d0c6d2011-03-01 13:19:07 -0800547 if (IS_ERR(dst))
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800548 goto out;
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800549 }
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800550
551 newsk = dccp_create_openreq_child(sk, req, skb);
552 if (newsk == NULL)
Balazs Scheidler093d2822010-10-21 13:06:43 +0200553 goto out_nonewsk;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800554
555 /*
556 * No need to charge this sock to the relevant IPv6 refcnt debug socks
557 * count here, dccp_create_openreq_child now does this for us, see the
558 * comment in that function for the gory details. -acme
559 */
560
YOSHIFUJI Hideaki8e1ef0a2006-08-29 17:15:09 -0700561 __ip6_dst_store(newsk, dst, NULL, NULL);
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800562 newsk->sk_route_caps = dst->dev->features & ~(NETIF_F_IP_CSUM |
563 NETIF_F_TSO);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800564 newdp6 = (struct dccp6_sock *)newsk;
565 newinet = inet_sk(newsk);
566 newinet->pinet6 = &newdp6->inet6;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800567 newnp = inet6_sk(newsk);
568
569 memcpy(newnp, np, sizeof(struct ipv6_pinfo));
570
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +0000571 newnp->daddr = ireq6->rmt_addr;
572 newnp->saddr = ireq6->loc_addr;
573 newnp->rcv_saddr = ireq6->loc_addr;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800574 newsk->sk_bound_dev_if = ireq6->iif;
575
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800576 /* Now IPv6 options...
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800577
578 First: no IPv4 options.
579 */
Eric Dumazetf6d8bd02011-04-21 09:45:37 +0000580 newinet->inet_opt = NULL;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800581
582 /* Clone RX bits */
583 newnp->rxopt.all = np->rxopt.all;
584
WANG Cong63572be2017-08-16 16:04:14 +0800585 newnp->ipv6_mc_list = NULL;
586 newnp->ipv6_ac_list = NULL;
587 newnp->ipv6_fl_list = NULL;
588
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800589 /* Clone pktoptions received with SYN */
590 newnp->pktoptions = NULL;
591 if (ireq6->pktopts != NULL) {
592 newnp->pktoptions = skb_clone(ireq6->pktopts, GFP_ATOMIC);
593 kfree_skb(ireq6->pktopts);
594 ireq6->pktopts = NULL;
595 if (newnp->pktoptions)
596 skb_set_owner_r(newnp->pktoptions, newsk);
597 }
598 newnp->opt = NULL;
599 newnp->mcast_oif = inet6_iif(skb);
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700600 newnp->mcast_hops = ipv6_hdr(skb)->hop_limit;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800601
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800602 /*
603 * Clone native IPv6 options from listening socket (if any)
604 *
605 * Yes, keeping reference count would be much more clever, but we make
606 * one more one thing there: reattach optmem to newsk.
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800607 */
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800608
Eric Dumazeta432b342015-11-29 19:37:57 -0800609 opt = rcu_dereference(np->opt);
610 if (opt) {
611 opt = ipv6_dup_options(newsk, opt);
612 RCU_INIT_POINTER(newnp->opt, opt);
613 }
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -0800614 inet_csk(newsk)->icsk_ext_hdr_len = 0;
Eric Dumazeta432b342015-11-29 19:37:57 -0800615 if (opt)
616 inet_csk(newsk)->icsk_ext_hdr_len = opt->opt_nflen +
617 opt->opt_flen;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800618
619 dccp_sync_mss(newsk, dst_mtu(dst));
620
Eric Dumazetc720c7e2009-10-15 06:30:45 +0000621 newinet->inet_daddr = newinet->inet_saddr = LOOPBACK4_IPV6;
622 newinet->inet_rcv_saddr = LOOPBACK4_IPV6;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800623
Balazs Scheidler093d2822010-10-21 13:06:43 +0200624 if (__inet_inherit_port(sk, newsk) < 0) {
Christoph Paaschefba1bb2012-12-14 04:07:58 +0000625 inet_csk_prepare_forced_close(newsk);
626 dccp_done(newsk);
Balazs Scheidler093d2822010-10-21 13:06:43 +0200627 goto out;
628 }
Eric Dumazet9327f702009-12-04 03:46:54 +0000629 __inet6_hash(newsk, NULL);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800630
631 return newsk;
632
633out_overflow:
Pavel Emelyanovde0744a2008-07-16 20:31:16 -0700634 NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENOVERFLOWS);
Balazs Scheidler093d2822010-10-21 13:06:43 +0200635out_nonewsk:
636 dst_release(dst);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800637out:
Pavel Emelyanovde0744a2008-07-16 20:31:16 -0700638 NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENDROPS);
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800639 if (opt != NULL && opt != np->opt)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800640 sock_kfree_s(sk, opt, opt->tot_len);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800641 return NULL;
642}
643
644/* The socket must have it's spinlock held when we get
645 * here.
646 *
647 * We have a potential double-lock case here, so even when
648 * doing backlog processing we use the BH locking scheme.
649 * This is because we cannot sleep with the original spinlock
650 * held.
651 */
652static int dccp_v6_do_rcv(struct sock *sk, struct sk_buff *skb)
653{
654 struct ipv6_pinfo *np = inet6_sk(sk);
655 struct sk_buff *opt_skb = NULL;
656
657 /* Imagine: socket is IPv6. IPv4 packet arrives,
658 goes to IPv4 receive handler and backlogged.
659 From backlog it always goes here. Kerboom...
660 Fortunately, dccp_rcv_established and rcv_established
661 handle them correctly, but it is not case with
662 dccp_v6_hnd_req and dccp_v6_ctl_send_reset(). --ANK
663 */
664
665 if (skb->protocol == htons(ETH_P_IP))
666 return dccp_v4_do_rcv(sk, skb);
667
Dmitry Mishinfda9ef52006-08-31 15:28:39 -0700668 if (sk_filter(sk, skb))
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800669 goto discard;
670
671 /*
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800672 * socket locking is here for SMP purposes as backlog rcv is currently
673 * called with bh processing disabled.
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800674 */
675
676 /* Do Stevens' IPV6_PKTOPTIONS.
677
678 Yes, guys, it is the only place in our code, where we
679 may make it not affecting IPv4.
680 The rest of code is protocol independent,
681 and I do not like idea to uglify IPv4.
682
683 Actually, all the idea behind IPV6_PKTOPTIONS
684 looks not very well thought. For now we latch
685 options, received in the last packet, enqueued
686 by tcp. Feel free to propose better solution.
YOSHIFUJI Hideakic9eaf172007-02-09 23:24:38 +0900687 --ANK (980728)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800688 */
689 if (np->rxopt.all)
Gerrit Renker89e7e572006-11-10 11:13:33 -0200690 /*
691 * FIXME: Add handling of IPV6_PKTOPTIONS skb. See the comments below
692 * (wrt ipv6_pktopions) and net/ipv6/tcp_ipv6.c for an example.
693 */
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800694 opt_skb = skb_clone(skb, GFP_ATOMIC);
695
696 if (sk->sk_state == DCCP_OPEN) { /* Fast path */
697 if (dccp_rcv_established(sk, skb, dccp_hdr(skb), skb->len))
698 goto reset;
David S. Millerfd169f12006-10-20 19:44:17 -0700699 if (opt_skb) {
Gerrit Renker89e7e572006-11-10 11:13:33 -0200700 /* XXX This is where we would goto ipv6_pktoptions. */
David S. Millerfd169f12006-10-20 19:44:17 -0700701 __kfree_skb(opt_skb);
702 }
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800703 return 0;
704 }
705
Gerrit Renkerd83ca5a2006-11-10 16:29:14 -0200706 /*
707 * Step 3: Process LISTEN state
708 * If S.state == LISTEN,
709 * If P.type == Request or P contains a valid Init Cookie option,
710 * (* Must scan the packet's options to check for Init
711 * Cookies. Only Init Cookies are processed here,
712 * however; other options are processed in Step 8. This
713 * scan need only be performed if the endpoint uses Init
714 * Cookies *)
715 * (* Generate a new socket and switch to that socket *)
716 * Set S := new socket for this port pair
717 * S.state = RESPOND
718 * Choose S.ISS (initial seqno) or set from Init Cookies
719 * Initialize S.GAR := S.ISS
720 * Set S.ISR, S.GSR, S.SWL, S.SWH from packet or Init Cookies
721 * Continue with S.state == RESPOND
722 * (* A Response packet will be generated in Step 11 *)
723 * Otherwise,
724 * Generate Reset(No Connection) unless P.type == Reset
725 * Drop packet and return
726 *
727 * NOTE: the check for the packet types is done in
728 * dccp_rcv_state_process
729 */
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800730 if (sk->sk_state == DCCP_LISTEN) {
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800731 struct sock *nsk = dccp_v6_hnd_req(sk, skb);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800732
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800733 if (nsk == NULL)
734 goto discard;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800735 /*
736 * Queue it on the new socket if the new socket is active,
737 * otherwise we just shortcircuit this and continue with
738 * the new socket..
739 */
Arnaldo Carvalho de Melo8109b022006-12-10 16:01:18 -0200740 if (nsk != sk) {
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800741 if (dccp_child_process(sk, nsk, skb))
742 goto reset;
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800743 if (opt_skb != NULL)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800744 __kfree_skb(opt_skb);
745 return 0;
746 }
747 }
748
749 if (dccp_rcv_state_process(sk, skb, dccp_hdr(skb), skb->len))
750 goto reset;
David S. Millerfd169f12006-10-20 19:44:17 -0700751 if (opt_skb) {
Gerrit Renker89e7e572006-11-10 11:13:33 -0200752 /* XXX This is where we would goto ipv6_pktoptions. */
David S. Millerfd169f12006-10-20 19:44:17 -0700753 __kfree_skb(opt_skb);
754 }
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800755 return 0;
756
757reset:
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800758 dccp_v6_ctl_send_reset(sk, skb);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800759discard:
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800760 if (opt_skb != NULL)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800761 __kfree_skb(opt_skb);
762 kfree_skb(skb);
763 return 0;
764}
765
Herbert Xue5bbef22007-10-15 12:50:28 -0700766static int dccp_v6_rcv(struct sk_buff *skb)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800767{
768 const struct dccp_hdr *dh;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800769 struct sock *sk;
Gerrit Renker6f4e5ff2006-11-10 17:43:06 -0200770 int min_cov;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800771
Gerrit Renker6f4e5ff2006-11-10 17:43:06 -0200772 /* Step 1: Check header basics */
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800773
774 if (dccp_invalid_packet(skb))
775 goto discard_it;
776
Gerrit Renker6f4e5ff2006-11-10 17:43:06 -0200777 /* Step 1: If header checksum is incorrect, drop packet and return. */
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700778 if (dccp_v6_csum_finish(skb, &ipv6_hdr(skb)->saddr,
779 &ipv6_hdr(skb)->daddr)) {
Gerrit Renker59348b12006-11-20 18:39:23 -0200780 DCCP_WARN("dropped packet with invalid checksum\n");
Gerrit Renker6f4e5ff2006-11-10 17:43:06 -0200781 goto discard_it;
782 }
783
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800784 dh = dccp_hdr(skb);
785
Gerrit Renkerfde20102007-10-24 10:12:09 -0200786 DCCP_SKB_CB(skb)->dccpd_seq = dccp_hdr_seq(dh);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800787 DCCP_SKB_CB(skb)->dccpd_type = dh->dccph_type;
788
789 if (dccp_packet_without_ack(skb))
790 DCCP_SKB_CB(skb)->dccpd_ack_seq = DCCP_PKT_WITHOUT_ACK_SEQ;
791 else
792 DCCP_SKB_CB(skb)->dccpd_ack_seq = dccp_hdr_ack_seq(skb);
793
794 /* Step 2:
Arnaldo Carvalho de Melo8109b022006-12-10 16:01:18 -0200795 * Look up flow ID in table and get corresponding socket */
Arnaldo Carvalho de Melo9a1f27c2008-10-07 11:41:57 -0700796 sk = __inet6_lookup_skb(&dccp_hashinfo, skb,
797 dh->dccph_sport, dh->dccph_dport);
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800798 /*
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800799 * Step 2:
Arnaldo Carvalho de Melo8109b022006-12-10 16:01:18 -0200800 * If no socket ...
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800801 */
Gerrit Renkerd23c7102006-11-10 11:46:34 -0200802 if (sk == NULL) {
803 dccp_pr_debug("failed to look up flow ID in table and "
804 "get corresponding socket\n");
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800805 goto no_dccp_socket;
Gerrit Renkerd23c7102006-11-10 11:46:34 -0200806 }
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800807
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800808 /*
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800809 * Step 2:
Arnaldo Carvalho de Melo8109b022006-12-10 16:01:18 -0200810 * ... or S.state == TIMEWAIT,
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800811 * Generate Reset(No Connection) unless P.type == Reset
812 * Drop packet and return
813 */
Gerrit Renkerd23c7102006-11-10 11:46:34 -0200814 if (sk->sk_state == DCCP_TIME_WAIT) {
815 dccp_pr_debug("sk->sk_state == DCCP_TIME_WAIT: do_time_wait\n");
816 inet_twsk_put(inet_twsk(sk));
817 goto no_dccp_socket;
818 }
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800819
Gerrit Renker6f4e5ff2006-11-10 17:43:06 -0200820 /*
821 * RFC 4340, sec. 9.2.1: Minimum Checksum Coverage
Arnaldo Carvalho de Melo8109b022006-12-10 16:01:18 -0200822 * o if MinCsCov = 0, only packets with CsCov = 0 are accepted
823 * o if MinCsCov > 0, also accept packets with CsCov >= MinCsCov
Gerrit Renker6f4e5ff2006-11-10 17:43:06 -0200824 */
825 min_cov = dccp_sk(sk)->dccps_pcrlen;
826 if (dh->dccph_cscov && (min_cov == 0 || dh->dccph_cscov < min_cov)) {
827 dccp_pr_debug("Packet CsCov %d does not satisfy MinCsCov %d\n",
828 dh->dccph_cscov, min_cov);
829 /* FIXME: send Data Dropped option (see also dccp_v4_rcv) */
830 goto discard_and_relse;
831 }
832
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800833 if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb))
834 goto discard_and_relse;
835
Arnaldo Carvalho de Melo58a5a7b2006-11-16 14:06:06 -0200836 return sk_receive_skb(sk, skb, 1) ? -1 : 0;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800837
838no_dccp_socket:
839 if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb))
840 goto discard_it;
841 /*
842 * Step 2:
Arnaldo Carvalho de Melo8109b022006-12-10 16:01:18 -0200843 * If no socket ...
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800844 * Generate Reset(No Connection) unless P.type == Reset
845 * Drop packet and return
846 */
847 if (dh->dccph_type != DCCP_PKT_RESET) {
848 DCCP_SKB_CB(skb)->dccpd_reset_code =
849 DCCP_RESET_CODE_NO_CONNECTION;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800850 dccp_v6_ctl_send_reset(sk, skb);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800851 }
Gerrit Renkerd23c7102006-11-10 11:46:34 -0200852
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800853discard_it:
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800854 kfree_skb(skb);
855 return 0;
856
857discard_and_relse:
858 sock_put(sk);
859 goto discard_it;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800860}
861
Gerrit Renker73c9e022006-11-10 13:01:31 -0200862static int dccp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
863 int addr_len)
864{
865 struct sockaddr_in6 *usin = (struct sockaddr_in6 *)uaddr;
866 struct inet_connection_sock *icsk = inet_csk(sk);
867 struct inet_sock *inet = inet_sk(sk);
868 struct ipv6_pinfo *np = inet6_sk(sk);
869 struct dccp_sock *dp = dccp_sk(sk);
Arnaud Ebalard20c59de2010-06-01 21:35:01 +0000870 struct in6_addr *saddr = NULL, *final_p, final;
Eric Dumazeta432b342015-11-29 19:37:57 -0800871 struct ipv6_txoptions *opt;
David S. Miller4c9483b2011-03-12 16:22:43 -0500872 struct flowi6 fl6;
Gerrit Renker73c9e022006-11-10 13:01:31 -0200873 struct dst_entry *dst;
874 int addr_type;
875 int err;
876
877 dp->dccps_role = DCCP_ROLE_CLIENT;
878
879 if (addr_len < SIN6_LEN_RFC2133)
880 return -EINVAL;
881
882 if (usin->sin6_family != AF_INET6)
883 return -EAFNOSUPPORT;
884
David S. Miller4c9483b2011-03-12 16:22:43 -0500885 memset(&fl6, 0, sizeof(fl6));
Gerrit Renker73c9e022006-11-10 13:01:31 -0200886
887 if (np->sndflow) {
David S. Miller4c9483b2011-03-12 16:22:43 -0500888 fl6.flowlabel = usin->sin6_flowinfo & IPV6_FLOWINFO_MASK;
889 IP6_ECN_flow_init(fl6.flowlabel);
890 if (fl6.flowlabel & IPV6_FLOWLABEL_MASK) {
Gerrit Renker73c9e022006-11-10 13:01:31 -0200891 struct ip6_flowlabel *flowlabel;
David S. Miller4c9483b2011-03-12 16:22:43 -0500892 flowlabel = fl6_sock_lookup(sk, fl6.flowlabel);
Gerrit Renker73c9e022006-11-10 13:01:31 -0200893 if (flowlabel == NULL)
894 return -EINVAL;
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +0000895 usin->sin6_addr = flowlabel->dst;
Gerrit Renker73c9e022006-11-10 13:01:31 -0200896 fl6_sock_release(flowlabel);
897 }
898 }
899 /*
900 * connect() to INADDR_ANY means loopback (BSD'ism).
901 */
902 if (ipv6_addr_any(&usin->sin6_addr))
903 usin->sin6_addr.s6_addr[15] = 1;
904
905 addr_type = ipv6_addr_type(&usin->sin6_addr);
906
907 if (addr_type & IPV6_ADDR_MULTICAST)
908 return -ENETUNREACH;
909
910 if (addr_type & IPV6_ADDR_LINKLOCAL) {
911 if (addr_len >= sizeof(struct sockaddr_in6) &&
912 usin->sin6_scope_id) {
913 /* If interface is set while binding, indices
914 * must coincide.
915 */
916 if (sk->sk_bound_dev_if &&
917 sk->sk_bound_dev_if != usin->sin6_scope_id)
918 return -EINVAL;
919
920 sk->sk_bound_dev_if = usin->sin6_scope_id;
921 }
922
923 /* Connect to link-local address requires an interface */
924 if (!sk->sk_bound_dev_if)
925 return -EINVAL;
926 }
927
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +0000928 np->daddr = usin->sin6_addr;
David S. Miller4c9483b2011-03-12 16:22:43 -0500929 np->flow_label = fl6.flowlabel;
Gerrit Renker73c9e022006-11-10 13:01:31 -0200930
931 /*
932 * DCCP over IPv4
933 */
934 if (addr_type == IPV6_ADDR_MAPPED) {
935 u32 exthdrlen = icsk->icsk_ext_hdr_len;
936 struct sockaddr_in sin;
937
938 SOCK_DEBUG(sk, "connect: ipv4 mapped\n");
939
940 if (__ipv6_only_sock(sk))
941 return -ENETUNREACH;
942
943 sin.sin_family = AF_INET;
944 sin.sin_port = usin->sin6_port;
945 sin.sin_addr.s_addr = usin->sin6_addr.s6_addr32[3];
946
947 icsk->icsk_af_ops = &dccp_ipv6_mapped;
948 sk->sk_backlog_rcv = dccp_v4_do_rcv;
949
950 err = dccp_v4_connect(sk, (struct sockaddr *)&sin, sizeof(sin));
951 if (err) {
952 icsk->icsk_ext_hdr_len = exthdrlen;
953 icsk->icsk_af_ops = &dccp_ipv6_af_ops;
954 sk->sk_backlog_rcv = dccp_v6_do_rcv;
955 goto failure;
Gerrit Renker73c9e022006-11-10 13:01:31 -0200956 }
Eric Dumazetc720c7e2009-10-15 06:30:45 +0000957 ipv6_addr_set_v4mapped(inet->inet_saddr, &np->saddr);
958 ipv6_addr_set_v4mapped(inet->inet_rcv_saddr, &np->rcv_saddr);
Gerrit Renker73c9e022006-11-10 13:01:31 -0200959
960 return err;
961 }
962
963 if (!ipv6_addr_any(&np->rcv_saddr))
964 saddr = &np->rcv_saddr;
965
David S. Miller4c9483b2011-03-12 16:22:43 -0500966 fl6.flowi6_proto = IPPROTO_DCCP;
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +0000967 fl6.daddr = np->daddr;
968 fl6.saddr = saddr ? *saddr : np->saddr;
David S. Miller4c9483b2011-03-12 16:22:43 -0500969 fl6.flowi6_oif = sk->sk_bound_dev_if;
David S. Miller1958b852011-03-12 16:36:19 -0500970 fl6.fl6_dport = usin->sin6_port;
971 fl6.fl6_sport = inet->inet_sport;
David S. Miller4c9483b2011-03-12 16:22:43 -0500972 security_sk_classify_flow(sk, flowi6_to_flowi(&fl6));
Gerrit Renker73c9e022006-11-10 13:01:31 -0200973
Eric Dumazeta432b342015-11-29 19:37:57 -0800974 opt = rcu_dereference_protected(np->opt, sock_owned_by_user(sk));
975 final_p = fl6_update_dst(&fl6, opt, &final);
Gerrit Renker73c9e022006-11-10 13:01:31 -0200976
David S. Miller4c9483b2011-03-12 16:22:43 -0500977 dst = ip6_dst_lookup_flow(sk, &fl6, final_p, true);
David S. Miller68d0c6d2011-03-01 13:19:07 -0800978 if (IS_ERR(dst)) {
979 err = PTR_ERR(dst);
Gerrit Renker73c9e022006-11-10 13:01:31 -0200980 goto failure;
David S. Miller14e50e52007-05-24 18:17:54 -0700981 }
Gerrit Renker73c9e022006-11-10 13:01:31 -0200982
983 if (saddr == NULL) {
David S. Miller4c9483b2011-03-12 16:22:43 -0500984 saddr = &fl6.saddr;
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +0000985 np->rcv_saddr = *saddr;
Gerrit Renker73c9e022006-11-10 13:01:31 -0200986 }
987
988 /* set the source address */
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +0000989 np->saddr = *saddr;
Eric Dumazetc720c7e2009-10-15 06:30:45 +0000990 inet->inet_rcv_saddr = LOOPBACK4_IPV6;
Gerrit Renker73c9e022006-11-10 13:01:31 -0200991
992 __ip6_dst_store(sk, dst, NULL, NULL);
993
994 icsk->icsk_ext_hdr_len = 0;
Eric Dumazeta432b342015-11-29 19:37:57 -0800995 if (opt)
996 icsk->icsk_ext_hdr_len = opt->opt_flen + opt->opt_nflen;
Gerrit Renker73c9e022006-11-10 13:01:31 -0200997
Eric Dumazetc720c7e2009-10-15 06:30:45 +0000998 inet->inet_dport = usin->sin6_port;
Gerrit Renker73c9e022006-11-10 13:01:31 -0200999
1000 dccp_set_state(sk, DCCP_REQUESTING);
1001 err = inet6_hash_connect(&dccp_death_row, sk);
1002 if (err)
1003 goto late_failure;
Gerrit Renkerd7f73652006-11-13 13:34:38 -02001004
1005 dp->dccps_iss = secure_dccpv6_sequence_number(np->saddr.s6_addr32,
1006 np->daddr.s6_addr32,
Eric Dumazetc720c7e2009-10-15 06:30:45 +00001007 inet->inet_sport,
1008 inet->inet_dport);
Gerrit Renker73c9e022006-11-10 13:01:31 -02001009 err = dccp_connect(sk);
1010 if (err)
1011 goto late_failure;
1012
1013 return 0;
1014
1015late_failure:
1016 dccp_set_state(sk, DCCP_CLOSED);
1017 __sk_dst_reset(sk);
1018failure:
Eric Dumazetc720c7e2009-10-15 06:30:45 +00001019 inet->inet_dport = 0;
Gerrit Renker73c9e022006-11-10 13:01:31 -02001020 sk->sk_route_caps = 0;
1021 return err;
1022}
1023
Stephen Hemminger3b401a82009-09-01 19:25:04 +00001024static const struct inet_connection_sock_af_ops dccp_ipv6_af_ops = {
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001025 .queue_xmit = inet6_csk_xmit,
1026 .send_check = dccp_v6_send_check,
1027 .rebuild_header = inet6_sk_rebuild_header,
1028 .conn_request = dccp_v6_conn_request,
1029 .syn_recv_sock = dccp_v6_request_recv_sock,
1030 .net_header_len = sizeof(struct ipv6hdr),
1031 .setsockopt = ipv6_setsockopt,
1032 .getsockopt = ipv6_getsockopt,
1033 .addr2sockaddr = inet6_csk_addr2sockaddr,
1034 .sockaddr_len = sizeof(struct sockaddr_in6),
Arnaldo Carvalho de Meloab1e0a12008-02-03 04:06:04 -08001035 .bind_conflict = inet6_csk_bind_conflict,
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001036#ifdef CONFIG_COMPAT
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001037 .compat_setsockopt = compat_ipv6_setsockopt,
1038 .compat_getsockopt = compat_ipv6_getsockopt,
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001039#endif
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001040};
1041
1042/*
1043 * DCCP over IPv4 via INET6 API
1044 */
Stephen Hemminger3b401a82009-09-01 19:25:04 +00001045static const struct inet_connection_sock_af_ops dccp_ipv6_mapped = {
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001046 .queue_xmit = ip_queue_xmit,
1047 .send_check = dccp_v4_send_check,
1048 .rebuild_header = inet_sk_rebuild_header,
1049 .conn_request = dccp_v6_conn_request,
1050 .syn_recv_sock = dccp_v6_request_recv_sock,
1051 .net_header_len = sizeof(struct iphdr),
1052 .setsockopt = ipv6_setsockopt,
1053 .getsockopt = ipv6_getsockopt,
1054 .addr2sockaddr = inet6_csk_addr2sockaddr,
1055 .sockaddr_len = sizeof(struct sockaddr_in6),
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001056#ifdef CONFIG_COMPAT
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001057 .compat_setsockopt = compat_ipv6_setsockopt,
1058 .compat_getsockopt = compat_ipv6_getsockopt,
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001059#endif
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001060};
1061
1062/* NOTE: A lot of things set to zero explicitly by call to
1063 * sk_alloc() so need not be done here.
1064 */
1065static int dccp_v6_init_sock(struct sock *sk)
1066{
Arnaldo Carvalho de Melo72478872006-03-20 22:00:37 -08001067 static __u8 dccp_v6_ctl_sock_initialized;
1068 int err = dccp_init_sock(sk, dccp_v6_ctl_sock_initialized);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001069
Arnaldo Carvalho de Melo72478872006-03-20 22:00:37 -08001070 if (err == 0) {
1071 if (unlikely(!dccp_v6_ctl_sock_initialized))
1072 dccp_v6_ctl_sock_initialized = 1;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001073 inet_csk(sk)->icsk_af_ops = &dccp_ipv6_af_ops;
Arnaldo Carvalho de Melo72478872006-03-20 22:00:37 -08001074 }
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001075
1076 return err;
1077}
1078
Brian Haley7d06b2e2008-06-14 17:04:49 -07001079static void dccp_v6_destroy_sock(struct sock *sk)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001080{
Arnaldo Carvalho de Melo3e0fadc2006-03-20 21:23:15 -08001081 dccp_destroy_sock(sk);
Brian Haley7d06b2e2008-06-14 17:04:49 -07001082 inet6_destroy_sock(sk);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001083}
1084
Gerrit Renker73c9e022006-11-10 13:01:31 -02001085static struct timewait_sock_ops dccp6_timewait_sock_ops = {
1086 .twsk_obj_size = sizeof(struct dccp6_timewait_sock),
1087};
1088
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001089static struct proto dccp_v6_prot = {
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001090 .name = "DCCPv6",
1091 .owner = THIS_MODULE,
1092 .close = dccp_close,
1093 .connect = dccp_v6_connect,
1094 .disconnect = dccp_disconnect,
1095 .ioctl = dccp_ioctl,
1096 .init = dccp_v6_init_sock,
1097 .setsockopt = dccp_setsockopt,
1098 .getsockopt = dccp_getsockopt,
1099 .sendmsg = dccp_sendmsg,
1100 .recvmsg = dccp_recvmsg,
1101 .backlog_rcv = dccp_v6_do_rcv,
1102 .hash = dccp_v6_hash,
Arnaldo Carvalho de Meloab1e0a12008-02-03 04:06:04 -08001103 .unhash = inet_unhash,
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001104 .accept = inet_csk_accept,
Arnaldo Carvalho de Meloab1e0a12008-02-03 04:06:04 -08001105 .get_port = inet_csk_get_port,
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001106 .shutdown = dccp_shutdown,
1107 .destroy = dccp_v6_destroy_sock,
1108 .orphan_count = &dccp_orphan_count,
1109 .max_header = MAX_DCCP_HEADER,
1110 .obj_size = sizeof(struct dccp6_sock),
Eric Dumazet3ab5aee2008-11-16 19:40:17 -08001111 .slab_flags = SLAB_DESTROY_BY_RCU,
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001112 .rsk_prot = &dccp6_request_sock_ops,
1113 .twsk_prot = &dccp6_timewait_sock_ops,
Pavel Emelyanov39d8cda2008-03-22 16:50:58 -07001114 .h.hashinfo = &dccp_hashinfo,
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001115#ifdef CONFIG_COMPAT
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001116 .compat_setsockopt = compat_dccp_setsockopt,
1117 .compat_getsockopt = compat_dccp_getsockopt,
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001118#endif
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001119};
1120
Alexey Dobriyan41135cc2009-09-14 12:22:28 +00001121static const struct inet6_protocol dccp_v6_protocol = {
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -08001122 .handler = dccp_v6_rcv,
1123 .err_handler = dccp_v6_err,
1124 .flags = INET6_PROTO_NOPOLICY | INET6_PROTO_FINAL,
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001125};
1126
Alexey Dobriyan5708e862009-09-14 12:23:23 +00001127static const struct proto_ops inet6_dccp_ops = {
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001128 .family = PF_INET6,
1129 .owner = THIS_MODULE,
1130 .release = inet6_release,
1131 .bind = inet6_bind,
1132 .connect = inet_stream_connect,
1133 .socketpair = sock_no_socketpair,
1134 .accept = inet_accept,
1135 .getname = inet6_getname,
1136 .poll = dccp_poll,
1137 .ioctl = inet6_ioctl,
1138 .listen = inet_dccp_listen,
1139 .shutdown = inet_shutdown,
1140 .setsockopt = sock_common_setsockopt,
1141 .getsockopt = sock_common_getsockopt,
1142 .sendmsg = inet_sendmsg,
1143 .recvmsg = sock_common_recvmsg,
1144 .mmap = sock_no_mmap,
1145 .sendpage = sock_no_sendpage,
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001146#ifdef CONFIG_COMPAT
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001147 .compat_setsockopt = compat_sock_common_setsockopt,
1148 .compat_getsockopt = compat_sock_common_getsockopt,
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001149#endif
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001150};
1151
1152static struct inet_protosw dccp_v6_protosw = {
1153 .type = SOCK_DCCP,
1154 .protocol = IPPROTO_DCCP,
1155 .prot = &dccp_v6_prot,
1156 .ops = &inet6_dccp_ops,
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -08001157 .flags = INET_PROTOSW_ICSK,
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001158};
1159
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00001160static int __net_init dccp_v6_init_net(struct net *net)
Pavel Emelyanov8231bd22008-04-13 22:32:02 -07001161{
Gerrit Renkerd14a0eb2010-03-14 20:13:19 +00001162 if (dccp_hashinfo.bhash == NULL)
1163 return -ESOCKTNOSUPPORT;
Pavel Emelyanov334527d2008-04-13 22:32:45 -07001164
Gerrit Renkerd14a0eb2010-03-14 20:13:19 +00001165 return inet_ctl_sock_create(&net->dccp.v6_ctl_sk, PF_INET6,
1166 SOCK_DCCP, IPPROTO_DCCP, net);
Pavel Emelyanov8231bd22008-04-13 22:32:02 -07001167}
1168
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00001169static void __net_exit dccp_v6_exit_net(struct net *net)
Pavel Emelyanov8231bd22008-04-13 22:32:02 -07001170{
Pavel Emelyanov334527d2008-04-13 22:32:45 -07001171 inet_ctl_sock_destroy(net->dccp.v6_ctl_sk);
Pavel Emelyanov8231bd22008-04-13 22:32:02 -07001172}
1173
1174static struct pernet_operations dccp_v6_ops = {
1175 .init = dccp_v6_init_net,
1176 .exit = dccp_v6_exit_net,
1177};
1178
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001179static int __init dccp_v6_init(void)
1180{
1181 int err = proto_register(&dccp_v6_prot, 1);
1182
1183 if (err != 0)
1184 goto out;
1185
1186 err = inet6_add_protocol(&dccp_v6_protocol, IPPROTO_DCCP);
1187 if (err != 0)
1188 goto out_unregister_proto;
1189
1190 inet6_register_protosw(&dccp_v6_protosw);
Arnaldo Carvalho de Melo72478872006-03-20 22:00:37 -08001191
Pavel Emelyanov8231bd22008-04-13 22:32:02 -07001192 err = register_pernet_subsys(&dccp_v6_ops);
1193 if (err != 0)
1194 goto out_destroy_ctl_sock;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001195out:
1196 return err;
Pavel Emelyanov8231bd22008-04-13 22:32:02 -07001197
1198out_destroy_ctl_sock:
Arnaldo Carvalho de Melo72478872006-03-20 22:00:37 -08001199 inet6_del_protocol(&dccp_v6_protocol, IPPROTO_DCCP);
1200 inet6_unregister_protosw(&dccp_v6_protosw);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001201out_unregister_proto:
1202 proto_unregister(&dccp_v6_prot);
1203 goto out;
1204}
1205
1206static void __exit dccp_v6_exit(void)
1207{
Pavel Emelyanov8231bd22008-04-13 22:32:02 -07001208 unregister_pernet_subsys(&dccp_v6_ops);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001209 inet6_del_protocol(&dccp_v6_protocol, IPPROTO_DCCP);
1210 inet6_unregister_protosw(&dccp_v6_protosw);
1211 proto_unregister(&dccp_v6_prot);
1212}
1213
1214module_init(dccp_v6_init);
1215module_exit(dccp_v6_exit);
1216
1217/*
1218 * __stringify doesn't likes enums, so use SOCK_DCCP (6) and IPPROTO_DCCP (33)
1219 * values directly, Also cover the case where the protocol is not specified,
1220 * i.e. net-pf-PF_INET6-proto-0-type-SOCK_DCCP
1221 */
Jean Delvare7131c6c2007-10-21 16:45:03 -07001222MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_INET6, 33, 6);
1223MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_INET6, 0, 6);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001224MODULE_LICENSE("GPL");
1225MODULE_AUTHOR("Arnaldo Carvalho de Melo <acme@mandriva.com>");
1226MODULE_DESCRIPTION("DCCPv6 - Datagram Congestion Controlled Protocol");