blob: b4d7d28ce6d23f69dec1686c918afa01d5b9fd23 [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
David S. Millerec18d9a2012-07-12 00:25:15 -0700133 if (type == NDISC_REDIRECT) {
134 struct dst_entry *dst = __sk_dst_check(sk, np->dst_cookie);
135
136 if (dst && dst->ops->redirect)
137 dst->ops->redirect(dst, skb);
138 }
139
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800140 if (type == ICMPV6_PKT_TOOBIG) {
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800141 struct dst_entry *dst = NULL;
142
143 if (sock_owned_by_user(sk))
144 goto out;
145 if ((1 << sk->sk_state) & (DCCPF_LISTEN | DCCPF_CLOSED))
146 goto out;
147
148 /* icmp should have updated the destination cache entry */
149 dst = __sk_dst_check(sk, np->dst_cookie);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800150 if (dst == NULL) {
151 struct inet_sock *inet = inet_sk(sk);
David S. Miller4c9483b2011-03-12 16:22:43 -0500152 struct flowi6 fl6;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800153
154 /* BUGGG_FUTURE: Again, it is not clear how
155 to handle rthdr case. Ignore this complexity
156 for now.
157 */
David S. Miller4c9483b2011-03-12 16:22:43 -0500158 memset(&fl6, 0, sizeof(fl6));
159 fl6.flowi6_proto = IPPROTO_DCCP;
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +0000160 fl6.daddr = np->daddr;
161 fl6.saddr = np->saddr;
David S. Miller4c9483b2011-03-12 16:22:43 -0500162 fl6.flowi6_oif = sk->sk_bound_dev_if;
David S. Miller1958b852011-03-12 16:36:19 -0500163 fl6.fl6_dport = inet->inet_dport;
164 fl6.fl6_sport = inet->inet_sport;
David S. Miller4c9483b2011-03-12 16:22:43 -0500165 security_sk_classify_flow(sk, flowi6_to_flowi(&fl6));
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800166
David S. Miller4c9483b2011-03-12 16:22:43 -0500167 dst = ip6_dst_lookup_flow(sk, &fl6, NULL, false);
David S. Miller68d0c6d2011-03-01 13:19:07 -0800168 if (IS_ERR(dst)) {
169 sk->sk_err_soft = -PTR_ERR(dst);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800170 goto out;
171 }
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800172 } else
173 dst_hold(dst);
174
David S. Miller81aded22012-06-15 14:54:11 -0700175 dst->ops->update_pmtu(dst, ntohl(info));
176
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -0800177 if (inet_csk(sk)->icsk_pmtu_cookie > dst_mtu(dst)) {
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800178 dccp_sync_mss(sk, dst_mtu(dst));
179 } /* else let the usual retransmit timer handle it */
180 dst_release(dst);
181 goto out;
182 }
183
184 icmpv6_err_convert(type, code, &err);
185
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800186 /* Might be for an request_sock */
187 switch (sk->sk_state) {
188 struct request_sock *req, **prev;
189 case DCCP_LISTEN:
190 if (sock_owned_by_user(sk))
191 goto out;
192
193 req = inet6_csk_search_req(sk, &prev, dh->dccph_dport,
194 &hdr->daddr, &hdr->saddr,
195 inet6_iif(skb));
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800196 if (req == NULL)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800197 goto out;
198
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800199 /*
200 * ICMPs are not backlogged, hence we cannot get an established
201 * socket here.
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800202 */
Ilpo Järvinen547b7922008-07-25 21:43:18 -0700203 WARN_ON(req->sk != NULL);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800204
Samuel Jerof541fb72012-02-26 18:22:02 -0700205 if (!between48(seq, dccp_rsk(req)->dreq_iss,
206 dccp_rsk(req)->dreq_gss)) {
Pavel Emelyanovde0744a2008-07-16 20:31:16 -0700207 NET_INC_STATS_BH(net, LINUX_MIB_OUTOFWINDOWICMPS);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800208 goto out;
209 }
210
211 inet_csk_reqsk_queue_drop(sk, req, prev);
212 goto out;
213
214 case DCCP_REQUESTING:
215 case DCCP_RESPOND: /* Cannot happen.
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800216 It can, it SYNs are crossed. --ANK */
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800217 if (!sock_owned_by_user(sk)) {
218 DCCP_INC_STATS_BH(DCCP_MIB_ATTEMPTFAILS);
219 sk->sk_err = err;
220 /*
221 * Wake people up to see the error
222 * (see connect in sock.c)
223 */
224 sk->sk_error_report(sk);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800225 dccp_done(sk);
226 } else
227 sk->sk_err_soft = err;
228 goto out;
229 }
230
231 if (!sock_owned_by_user(sk) && np->recverr) {
232 sk->sk_err = err;
233 sk->sk_error_report(sk);
234 } else
235 sk->sk_err_soft = err;
236
237out:
238 bh_unlock_sock(sk);
239 sock_put(sk);
240}
241
242
William Allen Simpsone6b4d112009-12-02 18:07:39 +0000243static int dccp_v6_send_response(struct sock *sk, struct request_sock *req,
244 struct request_values *rv_unused)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800245{
246 struct inet6_request_sock *ireq6 = inet6_rsk(req);
247 struct ipv6_pinfo *np = inet6_sk(sk);
248 struct sk_buff *skb;
Arnaud Ebalard20c59de2010-06-01 21:35:01 +0000249 struct in6_addr *final_p, final;
David S. Miller4c9483b2011-03-12 16:22:43 -0500250 struct flowi6 fl6;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800251 int err = -1;
Denis V. Lunevfd80eb92008-02-29 11:43:03 -0800252 struct dst_entry *dst;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800253
David S. Miller4c9483b2011-03-12 16:22:43 -0500254 memset(&fl6, 0, sizeof(fl6));
255 fl6.flowi6_proto = IPPROTO_DCCP;
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +0000256 fl6.daddr = ireq6->rmt_addr;
257 fl6.saddr = ireq6->loc_addr;
David S. Miller4c9483b2011-03-12 16:22:43 -0500258 fl6.flowlabel = 0;
259 fl6.flowi6_oif = ireq6->iif;
David S. Miller1958b852011-03-12 16:36:19 -0500260 fl6.fl6_dport = inet_rsk(req)->rmt_port;
261 fl6.fl6_sport = inet_rsk(req)->loc_port;
David S. Miller4c9483b2011-03-12 16:22:43 -0500262 security_req_classify_flow(req, flowi6_to_flowi(&fl6));
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800263
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800264
RongQing.Li0979e462012-07-01 17:19:00 +0000265 final_p = fl6_update_dst(&fl6, np->opt, &final);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800266
David S. Miller4c9483b2011-03-12 16:22:43 -0500267 dst = ip6_dst_lookup_flow(sk, &fl6, final_p, false);
David S. Miller68d0c6d2011-03-01 13:19:07 -0800268 if (IS_ERR(dst)) {
269 err = PTR_ERR(dst);
270 dst = NULL;
Denis V. Lunevfd80eb92008-02-29 11:43:03 -0800271 goto done;
David S. Miller68d0c6d2011-03-01 13:19:07 -0800272 }
Denis V. Lunevfd80eb92008-02-29 11:43:03 -0800273
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800274 skb = dccp_make_response(sk, dst, req);
275 if (skb != NULL) {
276 struct dccp_hdr *dh = dccp_hdr(skb);
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800277
Gerrit Renker6f4e5ff2006-11-10 17:43:06 -0200278 dh->dccph_checksum = dccp_v6_csum_finish(skb,
279 &ireq6->loc_addr,
280 &ireq6->rmt_addr);
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +0000281 fl6.daddr = ireq6->rmt_addr;
RongQing.Li0979e462012-07-01 17:19:00 +0000282 err = ip6_xmit(sk, skb, &fl6, np->opt, np->tclass);
Gerrit Renkerb9df3cb2006-11-14 11:21:36 -0200283 err = net_xmit_eval(err);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800284 }
285
286done:
David S. Miller0cbd7822006-01-31 17:53:37 -0800287 dst_release(dst);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800288 return err;
289}
290
291static void dccp_v6_reqsk_destructor(struct request_sock *req)
292{
Gerrit Renkerd99a7bd2008-11-04 23:56:30 -0800293 dccp_feat_list_purge(&dccp_rsk(req)->dreq_featneg);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800294 if (inet6_rsk(req)->pktopts != NULL)
295 kfree_skb(inet6_rsk(req)->pktopts);
296}
297
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800298static void dccp_v6_ctl_send_reset(struct sock *sk, struct sk_buff *rxskb)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800299{
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000300 const struct ipv6hdr *rxip6h;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800301 struct sk_buff *skb;
David S. Miller4c9483b2011-03-12 16:22:43 -0500302 struct flowi6 fl6;
Eric Dumazetadf30902009-06-02 05:19:30 +0000303 struct net *net = dev_net(skb_dst(rxskb)->dev);
Pavel Emelyanov334527d2008-04-13 22:32:45 -0700304 struct sock *ctl_sk = net->dccp.v6_ctl_sk;
Eric Dumazetadf30902009-06-02 05:19:30 +0000305 struct dst_entry *dst;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800306
Gerrit Renkere356d372007-09-26 14:35:19 -0300307 if (dccp_hdr(rxskb)->dccph_type == DCCP_PKT_RESET)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800308 return;
309
310 if (!ipv6_unicast_destination(rxskb))
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800311 return;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800312
Pavel Emelyanov02047742008-04-13 22:32:25 -0700313 skb = dccp_ctl_make_reset(ctl_sk, rxskb);
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800314 if (skb == NULL)
Arnaldo Carvalho de Melo8109b022006-12-10 16:01:18 -0200315 return;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800316
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700317 rxip6h = ipv6_hdr(rxskb);
Gerrit Renkere356d372007-09-26 14:35:19 -0300318 dccp_hdr(skb)->dccph_checksum = dccp_v6_csum_finish(skb, &rxip6h->saddr,
319 &rxip6h->daddr);
Gerrit Renker6f4e5ff2006-11-10 17:43:06 -0200320
David S. Miller4c9483b2011-03-12 16:22:43 -0500321 memset(&fl6, 0, sizeof(fl6));
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +0000322 fl6.daddr = rxip6h->saddr;
323 fl6.saddr = rxip6h->daddr;
Gerrit Renker6f4e5ff2006-11-10 17:43:06 -0200324
David S. Miller4c9483b2011-03-12 16:22:43 -0500325 fl6.flowi6_proto = IPPROTO_DCCP;
326 fl6.flowi6_oif = inet6_iif(rxskb);
David S. Miller1958b852011-03-12 16:36:19 -0500327 fl6.fl6_dport = dccp_hdr(skb)->dccph_dport;
328 fl6.fl6_sport = dccp_hdr(skb)->dccph_sport;
David S. Miller4c9483b2011-03-12 16:22:43 -0500329 security_skb_classify_flow(rxskb, flowi6_to_flowi(&fl6));
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800330
331 /* sk = NULL, but it is safe for now. RST socket required. */
David S. Miller4c9483b2011-03-12 16:22:43 -0500332 dst = ip6_dst_lookup_flow(ctl_sk, &fl6, NULL, false);
David S. Miller68d0c6d2011-03-01 13:19:07 -0800333 if (!IS_ERR(dst)) {
334 skb_dst_set(skb, dst);
Eric Dumazetb903d322011-10-27 00:44:35 -0400335 ip6_xmit(ctl_sk, skb, &fl6, NULL, 0);
David S. Miller68d0c6d2011-03-01 13:19:07 -0800336 DCCP_INC_STATS_BH(DCCP_MIB_OUTSEGS);
337 DCCP_INC_STATS_BH(DCCP_MIB_OUTRSTS);
338 return;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800339 }
340
341 kfree_skb(skb);
342}
343
Gerrit Renker73c9e022006-11-10 13:01:31 -0200344static struct request_sock_ops dccp6_request_sock_ops = {
345 .family = AF_INET6,
346 .obj_size = sizeof(struct dccp6_request_sock),
347 .rtx_syn_ack = dccp_v6_send_response,
348 .send_ack = dccp_reqsk_send_ack,
349 .destructor = dccp_v6_reqsk_destructor,
350 .send_reset = dccp_v6_ctl_send_reset,
Eric Dumazetc72e1182012-04-12 22:16:05 +0000351 .syn_ack_timeout = dccp_syn_ack_timeout,
Gerrit Renker73c9e022006-11-10 13:01:31 -0200352};
353
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800354static struct sock *dccp_v6_hnd_req(struct sock *sk,struct sk_buff *skb)
355{
356 const struct dccp_hdr *dh = dccp_hdr(skb);
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700357 const struct ipv6hdr *iph = ipv6_hdr(skb);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800358 struct sock *nsk;
359 struct request_sock **prev;
360 /* Find possible connection requests. */
361 struct request_sock *req = inet6_csk_search_req(sk, &prev,
362 dh->dccph_sport,
363 &iph->saddr,
364 &iph->daddr,
365 inet6_iif(skb));
366 if (req != NULL)
367 return dccp_check_req(sk, skb, req, prev);
368
Pavel Emelyanov671a1c72008-04-13 22:33:06 -0700369 nsk = __inet6_lookup_established(sock_net(sk), &dccp_hashinfo,
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800370 &iph->saddr, dh->dccph_sport,
371 &iph->daddr, ntohs(dh->dccph_dport),
372 inet6_iif(skb));
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800373 if (nsk != NULL) {
374 if (nsk->sk_state != DCCP_TIME_WAIT) {
375 bh_lock_sock(nsk);
376 return nsk;
377 }
YOSHIFUJI Hideaki9469c7b2006-10-10 19:41:46 -0700378 inet_twsk_put(inet_twsk(nsk));
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800379 return NULL;
380 }
381
382 return sk;
383}
384
385static int dccp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
386{
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800387 struct request_sock *req;
388 struct dccp_request_sock *dreq;
389 struct inet6_request_sock *ireq6;
390 struct ipv6_pinfo *np = inet6_sk(sk);
Arnaldo Carvalho de Melo8109b022006-12-10 16:01:18 -0200391 const __be32 service = dccp_hdr_request(skb)->dccph_req_service;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800392 struct dccp_skb_cb *dcb = DCCP_SKB_CB(skb);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800393
394 if (skb->protocol == htons(ETH_P_IP))
395 return dccp_v4_conn_request(sk, skb);
396
397 if (!ipv6_unicast_destination(skb))
Gerrit Renker4a5409a2007-10-04 14:52:28 -0700398 return 0; /* discard, don't send a reset here */
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800399
400 if (dccp_bad_service_code(sk, service)) {
Gerrit Renker4a5409a2007-10-04 14:52:28 -0700401 dcb->dccpd_reset_code = DCCP_RESET_CODE_BAD_SERVICE_CODE;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800402 goto drop;
Arnaldo Carvalho de Melo8109b022006-12-10 16:01:18 -0200403 }
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800404 /*
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800405 * There are no SYN attacks on IPv6, yet...
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800406 */
Gerrit Renker4a5409a2007-10-04 14:52:28 -0700407 dcb->dccpd_reset_code = DCCP_RESET_CODE_TOO_BUSY;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800408 if (inet_csk_reqsk_queue_is_full(sk))
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800409 goto drop;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800410
411 if (sk_acceptq_is_full(sk) && inet_csk_reqsk_queue_young(sk) > 1)
412 goto drop;
413
Gerrit Renker82709532006-10-11 16:26:54 +0100414 req = inet6_reqsk_alloc(&dccp6_request_sock_ops);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800415 if (req == NULL)
416 goto drop;
417
Gerrit Renkerac757732008-11-04 23:55:49 -0800418 if (dccp_reqsk_init(req, dccp_sk(sk), skb))
419 goto drop_and_free;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800420
Gerrit Renker8b819412007-12-13 12:29:24 -0200421 dreq = dccp_rsk(req);
422 if (dccp_parse_options(sk, dreq, skb))
423 goto drop_and_free;
424
Venkat Yekkirala4237c752006-07-24 23:32:50 -0700425 if (security_inet_conn_request(sk, skb, req))
426 goto drop_and_free;
427
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800428 ireq6 = inet6_rsk(req);
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +0000429 ireq6->rmt_addr = ipv6_hdr(skb)->saddr;
430 ireq6->loc_addr = ipv6_hdr(skb)->daddr;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800431
432 if (ipv6_opt_accepted(sk, skb) ||
433 np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo ||
434 np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim) {
435 atomic_inc(&skb->users);
436 ireq6->pktopts = skb;
437 }
438 ireq6->iif = sk->sk_bound_dev_if;
439
440 /* So that link locals have meaning */
441 if (!sk->sk_bound_dev_if &&
442 ipv6_addr_type(&ireq6->rmt_addr) & IPV6_ADDR_LINKLOCAL)
443 ireq6->iif = inet6_iif(skb);
444
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800445 /*
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800446 * Step 3: Process LISTEN state
447 *
Gerrit Renkerd83ca5a2006-11-10 16:29:14 -0200448 * Set S.ISR, S.GSR, S.SWL, S.SWH from packet or Init Cookie
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800449 *
Samuel Jerof541fb72012-02-26 18:22:02 -0700450 * Setting S.SWL/S.SWH to is deferred to dccp_create_openreq_child().
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800451 */
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800452 dreq->dreq_isr = dcb->dccpd_seq;
Samuel Jerof541fb72012-02-26 18:22:02 -0700453 dreq->dreq_gsr = dreq->dreq_isr;
Gerrit Renker865e9022006-11-13 13:31:50 -0200454 dreq->dreq_iss = dccp_v6_init_sequence(skb);
Samuel Jerof541fb72012-02-26 18:22:02 -0700455 dreq->dreq_gss = dreq->dreq_iss;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800456 dreq->dreq_service = service;
457
William Allen Simpsone6b4d112009-12-02 18:07:39 +0000458 if (dccp_v6_send_response(sk, req, NULL))
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800459 goto drop_and_free;
460
461 inet6_csk_reqsk_queue_hash_add(sk, req, DCCP_TIMEOUT_INIT);
462 return 0;
463
464drop_and_free:
465 reqsk_free(req);
466drop:
467 DCCP_INC_STATS_BH(DCCP_MIB_ATTEMPTFAILS);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800468 return -1;
469}
470
471static struct sock *dccp_v6_request_recv_sock(struct sock *sk,
472 struct sk_buff *skb,
473 struct request_sock *req,
474 struct dst_entry *dst)
475{
476 struct inet6_request_sock *ireq6 = inet6_rsk(req);
477 struct ipv6_pinfo *newnp, *np = inet6_sk(sk);
478 struct inet_sock *newinet;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800479 struct dccp6_sock *newdp6;
480 struct sock *newsk;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800481
482 if (skb->protocol == htons(ETH_P_IP)) {
483 /*
484 * v6 mapped
485 */
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800486 newsk = dccp_v4_request_recv_sock(sk, skb, req, dst);
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800487 if (newsk == NULL)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800488 return NULL;
489
490 newdp6 = (struct dccp6_sock *)newsk;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800491 newinet = inet_sk(newsk);
492 newinet->pinet6 = &newdp6->inet6;
493 newnp = inet6_sk(newsk);
494
495 memcpy(newnp, np, sizeof(struct ipv6_pinfo));
496
Eric Dumazetc720c7e2009-10-15 06:30:45 +0000497 ipv6_addr_set_v4mapped(newinet->inet_daddr, &newnp->daddr);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800498
Eric Dumazetc720c7e2009-10-15 06:30:45 +0000499 ipv6_addr_set_v4mapped(newinet->inet_saddr, &newnp->saddr);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800500
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +0000501 newnp->rcv_saddr = newnp->saddr;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800502
503 inet_csk(newsk)->icsk_af_ops = &dccp_ipv6_mapped;
504 newsk->sk_backlog_rcv = dccp_v4_do_rcv;
505 newnp->pktoptions = NULL;
506 newnp->opt = NULL;
507 newnp->mcast_oif = inet6_iif(skb);
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700508 newnp->mcast_hops = ipv6_hdr(skb)->hop_limit;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800509
510 /*
511 * No need to charge this sock to the relevant IPv6 refcnt debug socks count
512 * here, dccp_create_openreq_child now does this for us, see the comment in
513 * that function for the gory details. -acme
514 */
515
516 /* It is tricky place. Until this moment IPv4 tcp
517 worked with IPv6 icsk.icsk_af_ops.
518 Sync it now.
519 */
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -0800520 dccp_sync_mss(newsk, inet_csk(newsk)->icsk_pmtu_cookie);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800521
522 return newsk;
523 }
524
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800525
526 if (sk_acceptq_is_full(sk))
527 goto out_overflow;
528
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800529 if (dst == NULL) {
Arnaud Ebalard20c59de2010-06-01 21:35:01 +0000530 struct in6_addr *final_p, final;
David S. Miller4c9483b2011-03-12 16:22:43 -0500531 struct flowi6 fl6;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800532
David S. Miller4c9483b2011-03-12 16:22:43 -0500533 memset(&fl6, 0, sizeof(fl6));
534 fl6.flowi6_proto = IPPROTO_DCCP;
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +0000535 fl6.daddr = ireq6->rmt_addr;
RongQing.Li0979e462012-07-01 17:19:00 +0000536 final_p = fl6_update_dst(&fl6, np->opt, &final);
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +0000537 fl6.saddr = ireq6->loc_addr;
David S. Miller4c9483b2011-03-12 16:22:43 -0500538 fl6.flowi6_oif = sk->sk_bound_dev_if;
David S. Miller1958b852011-03-12 16:36:19 -0500539 fl6.fl6_dport = inet_rsk(req)->rmt_port;
540 fl6.fl6_sport = inet_rsk(req)->loc_port;
David S. Miller4c9483b2011-03-12 16:22:43 -0500541 security_sk_classify_flow(sk, flowi6_to_flowi(&fl6));
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800542
David S. Miller4c9483b2011-03-12 16:22:43 -0500543 dst = ip6_dst_lookup_flow(sk, &fl6, final_p, false);
David S. Miller68d0c6d2011-03-01 13:19:07 -0800544 if (IS_ERR(dst))
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800545 goto out;
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800546 }
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800547
548 newsk = dccp_create_openreq_child(sk, req, skb);
549 if (newsk == NULL)
Balazs Scheidler093d2822010-10-21 13:06:43 +0200550 goto out_nonewsk;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800551
552 /*
553 * No need to charge this sock to the relevant IPv6 refcnt debug socks
554 * count here, dccp_create_openreq_child now does this for us, see the
555 * comment in that function for the gory details. -acme
556 */
557
YOSHIFUJI Hideaki8e1ef0a2006-08-29 17:15:09 -0700558 __ip6_dst_store(newsk, dst, NULL, NULL);
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800559 newsk->sk_route_caps = dst->dev->features & ~(NETIF_F_IP_CSUM |
560 NETIF_F_TSO);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800561 newdp6 = (struct dccp6_sock *)newsk;
562 newinet = inet_sk(newsk);
563 newinet->pinet6 = &newdp6->inet6;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800564 newnp = inet6_sk(newsk);
565
566 memcpy(newnp, np, sizeof(struct ipv6_pinfo));
567
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +0000568 newnp->daddr = ireq6->rmt_addr;
569 newnp->saddr = ireq6->loc_addr;
570 newnp->rcv_saddr = ireq6->loc_addr;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800571 newsk->sk_bound_dev_if = ireq6->iif;
572
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800573 /* Now IPv6 options...
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800574
575 First: no IPv4 options.
576 */
Eric Dumazetf6d8bd02011-04-21 09:45:37 +0000577 newinet->inet_opt = NULL;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800578
579 /* Clone RX bits */
580 newnp->rxopt.all = np->rxopt.all;
581
582 /* Clone pktoptions received with SYN */
583 newnp->pktoptions = NULL;
584 if (ireq6->pktopts != NULL) {
585 newnp->pktoptions = skb_clone(ireq6->pktopts, GFP_ATOMIC);
Eric Dumazet7604adc2012-04-19 02:24:48 +0000586 consume_skb(ireq6->pktopts);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800587 ireq6->pktopts = NULL;
588 if (newnp->pktoptions)
589 skb_set_owner_r(newnp->pktoptions, newsk);
590 }
591 newnp->opt = NULL;
592 newnp->mcast_oif = inet6_iif(skb);
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700593 newnp->mcast_hops = ipv6_hdr(skb)->hop_limit;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800594
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800595 /*
596 * Clone native IPv6 options from listening socket (if any)
597 *
598 * Yes, keeping reference count would be much more clever, but we make
599 * one more one thing there: reattach optmem to newsk.
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800600 */
RongQing.Li0979e462012-07-01 17:19:00 +0000601 if (np->opt != NULL)
602 newnp->opt = ipv6_dup_options(newsk, np->opt);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800603
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -0800604 inet_csk(newsk)->icsk_ext_hdr_len = 0;
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800605 if (newnp->opt != NULL)
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -0800606 inet_csk(newsk)->icsk_ext_hdr_len = (newnp->opt->opt_nflen +
607 newnp->opt->opt_flen);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800608
609 dccp_sync_mss(newsk, dst_mtu(dst));
610
Eric Dumazetc720c7e2009-10-15 06:30:45 +0000611 newinet->inet_daddr = newinet->inet_saddr = LOOPBACK4_IPV6;
612 newinet->inet_rcv_saddr = LOOPBACK4_IPV6;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800613
Balazs Scheidler093d2822010-10-21 13:06:43 +0200614 if (__inet_inherit_port(sk, newsk) < 0) {
615 sock_put(newsk);
616 goto out;
617 }
Eric Dumazet9327f702009-12-04 03:46:54 +0000618 __inet6_hash(newsk, NULL);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800619
620 return newsk;
621
622out_overflow:
Pavel Emelyanovde0744a2008-07-16 20:31:16 -0700623 NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENOVERFLOWS);
Balazs Scheidler093d2822010-10-21 13:06:43 +0200624out_nonewsk:
625 dst_release(dst);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800626out:
Pavel Emelyanovde0744a2008-07-16 20:31:16 -0700627 NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENDROPS);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800628 return NULL;
629}
630
631/* The socket must have it's spinlock held when we get
632 * here.
633 *
634 * We have a potential double-lock case here, so even when
635 * doing backlog processing we use the BH locking scheme.
636 * This is because we cannot sleep with the original spinlock
637 * held.
638 */
639static int dccp_v6_do_rcv(struct sock *sk, struct sk_buff *skb)
640{
641 struct ipv6_pinfo *np = inet6_sk(sk);
642 struct sk_buff *opt_skb = NULL;
643
644 /* Imagine: socket is IPv6. IPv4 packet arrives,
645 goes to IPv4 receive handler and backlogged.
646 From backlog it always goes here. Kerboom...
647 Fortunately, dccp_rcv_established and rcv_established
648 handle them correctly, but it is not case with
649 dccp_v6_hnd_req and dccp_v6_ctl_send_reset(). --ANK
650 */
651
652 if (skb->protocol == htons(ETH_P_IP))
653 return dccp_v4_do_rcv(sk, skb);
654
Dmitry Mishinfda9ef52006-08-31 15:28:39 -0700655 if (sk_filter(sk, skb))
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800656 goto discard;
657
658 /*
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800659 * socket locking is here for SMP purposes as backlog rcv is currently
660 * called with bh processing disabled.
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800661 */
662
663 /* Do Stevens' IPV6_PKTOPTIONS.
664
665 Yes, guys, it is the only place in our code, where we
666 may make it not affecting IPv4.
667 The rest of code is protocol independent,
668 and I do not like idea to uglify IPv4.
669
670 Actually, all the idea behind IPV6_PKTOPTIONS
671 looks not very well thought. For now we latch
672 options, received in the last packet, enqueued
673 by tcp. Feel free to propose better solution.
YOSHIFUJI Hideakic9eaf172007-02-09 23:24:38 +0900674 --ANK (980728)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800675 */
676 if (np->rxopt.all)
Gerrit Renker89e7e572006-11-10 11:13:33 -0200677 /*
678 * FIXME: Add handling of IPV6_PKTOPTIONS skb. See the comments below
679 * (wrt ipv6_pktopions) and net/ipv6/tcp_ipv6.c for an example.
680 */
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800681 opt_skb = skb_clone(skb, GFP_ATOMIC);
682
683 if (sk->sk_state == DCCP_OPEN) { /* Fast path */
684 if (dccp_rcv_established(sk, skb, dccp_hdr(skb), skb->len))
685 goto reset;
David S. Millerfd169f12006-10-20 19:44:17 -0700686 if (opt_skb) {
Gerrit Renker89e7e572006-11-10 11:13:33 -0200687 /* XXX This is where we would goto ipv6_pktoptions. */
David S. Millerfd169f12006-10-20 19:44:17 -0700688 __kfree_skb(opt_skb);
689 }
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800690 return 0;
691 }
692
Gerrit Renkerd83ca5a2006-11-10 16:29:14 -0200693 /*
694 * Step 3: Process LISTEN state
695 * If S.state == LISTEN,
696 * If P.type == Request or P contains a valid Init Cookie option,
697 * (* Must scan the packet's options to check for Init
698 * Cookies. Only Init Cookies are processed here,
699 * however; other options are processed in Step 8. This
700 * scan need only be performed if the endpoint uses Init
701 * Cookies *)
702 * (* Generate a new socket and switch to that socket *)
703 * Set S := new socket for this port pair
704 * S.state = RESPOND
705 * Choose S.ISS (initial seqno) or set from Init Cookies
706 * Initialize S.GAR := S.ISS
707 * Set S.ISR, S.GSR, S.SWL, S.SWH from packet or Init Cookies
708 * Continue with S.state == RESPOND
709 * (* A Response packet will be generated in Step 11 *)
710 * Otherwise,
711 * Generate Reset(No Connection) unless P.type == Reset
712 * Drop packet and return
713 *
714 * NOTE: the check for the packet types is done in
715 * dccp_rcv_state_process
716 */
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800717 if (sk->sk_state == DCCP_LISTEN) {
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800718 struct sock *nsk = dccp_v6_hnd_req(sk, skb);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800719
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800720 if (nsk == NULL)
721 goto discard;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800722 /*
723 * Queue it on the new socket if the new socket is active,
724 * otherwise we just shortcircuit this and continue with
725 * the new socket..
726 */
Arnaldo Carvalho de Melo8109b022006-12-10 16:01:18 -0200727 if (nsk != sk) {
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800728 if (dccp_child_process(sk, nsk, skb))
729 goto reset;
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800730 if (opt_skb != NULL)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800731 __kfree_skb(opt_skb);
732 return 0;
733 }
734 }
735
736 if (dccp_rcv_state_process(sk, skb, dccp_hdr(skb), skb->len))
737 goto reset;
David S. Millerfd169f12006-10-20 19:44:17 -0700738 if (opt_skb) {
Gerrit Renker89e7e572006-11-10 11:13:33 -0200739 /* XXX This is where we would goto ipv6_pktoptions. */
David S. Millerfd169f12006-10-20 19:44:17 -0700740 __kfree_skb(opt_skb);
741 }
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800742 return 0;
743
744reset:
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800745 dccp_v6_ctl_send_reset(sk, skb);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800746discard:
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800747 if (opt_skb != NULL)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800748 __kfree_skb(opt_skb);
749 kfree_skb(skb);
750 return 0;
751}
752
Herbert Xue5bbef22007-10-15 12:50:28 -0700753static int dccp_v6_rcv(struct sk_buff *skb)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800754{
755 const struct dccp_hdr *dh;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800756 struct sock *sk;
Gerrit Renker6f4e5ff2006-11-10 17:43:06 -0200757 int min_cov;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800758
Gerrit Renker6f4e5ff2006-11-10 17:43:06 -0200759 /* Step 1: Check header basics */
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800760
761 if (dccp_invalid_packet(skb))
762 goto discard_it;
763
Gerrit Renker6f4e5ff2006-11-10 17:43:06 -0200764 /* Step 1: If header checksum is incorrect, drop packet and return. */
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700765 if (dccp_v6_csum_finish(skb, &ipv6_hdr(skb)->saddr,
766 &ipv6_hdr(skb)->daddr)) {
Gerrit Renker59348b12006-11-20 18:39:23 -0200767 DCCP_WARN("dropped packet with invalid checksum\n");
Gerrit Renker6f4e5ff2006-11-10 17:43:06 -0200768 goto discard_it;
769 }
770
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800771 dh = dccp_hdr(skb);
772
Gerrit Renkerfde20102007-10-24 10:12:09 -0200773 DCCP_SKB_CB(skb)->dccpd_seq = dccp_hdr_seq(dh);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800774 DCCP_SKB_CB(skb)->dccpd_type = dh->dccph_type;
775
776 if (dccp_packet_without_ack(skb))
777 DCCP_SKB_CB(skb)->dccpd_ack_seq = DCCP_PKT_WITHOUT_ACK_SEQ;
778 else
779 DCCP_SKB_CB(skb)->dccpd_ack_seq = dccp_hdr_ack_seq(skb);
780
781 /* Step 2:
Arnaldo Carvalho de Melo8109b022006-12-10 16:01:18 -0200782 * Look up flow ID in table and get corresponding socket */
Arnaldo Carvalho de Melo9a1f27c2008-10-07 11:41:57 -0700783 sk = __inet6_lookup_skb(&dccp_hashinfo, skb,
784 dh->dccph_sport, dh->dccph_dport);
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800785 /*
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800786 * Step 2:
Arnaldo Carvalho de Melo8109b022006-12-10 16:01:18 -0200787 * If no socket ...
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800788 */
Gerrit Renkerd23c7102006-11-10 11:46:34 -0200789 if (sk == NULL) {
790 dccp_pr_debug("failed to look up flow ID in table and "
791 "get corresponding socket\n");
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800792 goto no_dccp_socket;
Gerrit Renkerd23c7102006-11-10 11:46:34 -0200793 }
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800794
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -0800795 /*
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800796 * Step 2:
Arnaldo Carvalho de Melo8109b022006-12-10 16:01:18 -0200797 * ... or S.state == TIMEWAIT,
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800798 * Generate Reset(No Connection) unless P.type == Reset
799 * Drop packet and return
800 */
Gerrit Renkerd23c7102006-11-10 11:46:34 -0200801 if (sk->sk_state == DCCP_TIME_WAIT) {
802 dccp_pr_debug("sk->sk_state == DCCP_TIME_WAIT: do_time_wait\n");
803 inet_twsk_put(inet_twsk(sk));
804 goto no_dccp_socket;
805 }
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800806
Gerrit Renker6f4e5ff2006-11-10 17:43:06 -0200807 /*
808 * RFC 4340, sec. 9.2.1: Minimum Checksum Coverage
Arnaldo Carvalho de Melo8109b022006-12-10 16:01:18 -0200809 * o if MinCsCov = 0, only packets with CsCov = 0 are accepted
810 * o if MinCsCov > 0, also accept packets with CsCov >= MinCsCov
Gerrit Renker6f4e5ff2006-11-10 17:43:06 -0200811 */
812 min_cov = dccp_sk(sk)->dccps_pcrlen;
813 if (dh->dccph_cscov && (min_cov == 0 || dh->dccph_cscov < min_cov)) {
814 dccp_pr_debug("Packet CsCov %d does not satisfy MinCsCov %d\n",
815 dh->dccph_cscov, min_cov);
816 /* FIXME: send Data Dropped option (see also dccp_v4_rcv) */
817 goto discard_and_relse;
818 }
819
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800820 if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb))
821 goto discard_and_relse;
822
Arnaldo Carvalho de Melo58a5a7b2006-11-16 14:06:06 -0200823 return sk_receive_skb(sk, skb, 1) ? -1 : 0;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800824
825no_dccp_socket:
826 if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb))
827 goto discard_it;
828 /*
829 * Step 2:
Arnaldo Carvalho de Melo8109b022006-12-10 16:01:18 -0200830 * If no socket ...
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800831 * Generate Reset(No Connection) unless P.type == Reset
832 * Drop packet and return
833 */
834 if (dh->dccph_type != DCCP_PKT_RESET) {
835 DCCP_SKB_CB(skb)->dccpd_reset_code =
836 DCCP_RESET_CODE_NO_CONNECTION;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800837 dccp_v6_ctl_send_reset(sk, skb);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800838 }
Gerrit Renkerd23c7102006-11-10 11:46:34 -0200839
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800840discard_it:
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800841 kfree_skb(skb);
842 return 0;
843
844discard_and_relse:
845 sock_put(sk);
846 goto discard_it;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -0800847}
848
Gerrit Renker73c9e022006-11-10 13:01:31 -0200849static int dccp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
850 int addr_len)
851{
852 struct sockaddr_in6 *usin = (struct sockaddr_in6 *)uaddr;
853 struct inet_connection_sock *icsk = inet_csk(sk);
854 struct inet_sock *inet = inet_sk(sk);
855 struct ipv6_pinfo *np = inet6_sk(sk);
856 struct dccp_sock *dp = dccp_sk(sk);
Arnaud Ebalard20c59de2010-06-01 21:35:01 +0000857 struct in6_addr *saddr = NULL, *final_p, final;
David S. Miller4c9483b2011-03-12 16:22:43 -0500858 struct flowi6 fl6;
Gerrit Renker73c9e022006-11-10 13:01:31 -0200859 struct dst_entry *dst;
860 int addr_type;
861 int err;
862
863 dp->dccps_role = DCCP_ROLE_CLIENT;
864
865 if (addr_len < SIN6_LEN_RFC2133)
866 return -EINVAL;
867
868 if (usin->sin6_family != AF_INET6)
869 return -EAFNOSUPPORT;
870
David S. Miller4c9483b2011-03-12 16:22:43 -0500871 memset(&fl6, 0, sizeof(fl6));
Gerrit Renker73c9e022006-11-10 13:01:31 -0200872
873 if (np->sndflow) {
David S. Miller4c9483b2011-03-12 16:22:43 -0500874 fl6.flowlabel = usin->sin6_flowinfo & IPV6_FLOWINFO_MASK;
875 IP6_ECN_flow_init(fl6.flowlabel);
876 if (fl6.flowlabel & IPV6_FLOWLABEL_MASK) {
Gerrit Renker73c9e022006-11-10 13:01:31 -0200877 struct ip6_flowlabel *flowlabel;
David S. Miller4c9483b2011-03-12 16:22:43 -0500878 flowlabel = fl6_sock_lookup(sk, fl6.flowlabel);
Gerrit Renker73c9e022006-11-10 13:01:31 -0200879 if (flowlabel == NULL)
880 return -EINVAL;
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +0000881 usin->sin6_addr = flowlabel->dst;
Gerrit Renker73c9e022006-11-10 13:01:31 -0200882 fl6_sock_release(flowlabel);
883 }
884 }
885 /*
886 * connect() to INADDR_ANY means loopback (BSD'ism).
887 */
888 if (ipv6_addr_any(&usin->sin6_addr))
889 usin->sin6_addr.s6_addr[15] = 1;
890
891 addr_type = ipv6_addr_type(&usin->sin6_addr);
892
893 if (addr_type & IPV6_ADDR_MULTICAST)
894 return -ENETUNREACH;
895
896 if (addr_type & IPV6_ADDR_LINKLOCAL) {
897 if (addr_len >= sizeof(struct sockaddr_in6) &&
898 usin->sin6_scope_id) {
899 /* If interface is set while binding, indices
900 * must coincide.
901 */
902 if (sk->sk_bound_dev_if &&
903 sk->sk_bound_dev_if != usin->sin6_scope_id)
904 return -EINVAL;
905
906 sk->sk_bound_dev_if = usin->sin6_scope_id;
907 }
908
909 /* Connect to link-local address requires an interface */
910 if (!sk->sk_bound_dev_if)
911 return -EINVAL;
912 }
913
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +0000914 np->daddr = usin->sin6_addr;
David S. Miller4c9483b2011-03-12 16:22:43 -0500915 np->flow_label = fl6.flowlabel;
Gerrit Renker73c9e022006-11-10 13:01:31 -0200916
917 /*
918 * DCCP over IPv4
919 */
920 if (addr_type == IPV6_ADDR_MAPPED) {
921 u32 exthdrlen = icsk->icsk_ext_hdr_len;
922 struct sockaddr_in sin;
923
924 SOCK_DEBUG(sk, "connect: ipv4 mapped\n");
925
926 if (__ipv6_only_sock(sk))
927 return -ENETUNREACH;
928
929 sin.sin_family = AF_INET;
930 sin.sin_port = usin->sin6_port;
931 sin.sin_addr.s_addr = usin->sin6_addr.s6_addr32[3];
932
933 icsk->icsk_af_ops = &dccp_ipv6_mapped;
934 sk->sk_backlog_rcv = dccp_v4_do_rcv;
935
936 err = dccp_v4_connect(sk, (struct sockaddr *)&sin, sizeof(sin));
937 if (err) {
938 icsk->icsk_ext_hdr_len = exthdrlen;
939 icsk->icsk_af_ops = &dccp_ipv6_af_ops;
940 sk->sk_backlog_rcv = dccp_v6_do_rcv;
941 goto failure;
Gerrit Renker73c9e022006-11-10 13:01:31 -0200942 }
Eric Dumazetc720c7e2009-10-15 06:30:45 +0000943 ipv6_addr_set_v4mapped(inet->inet_saddr, &np->saddr);
944 ipv6_addr_set_v4mapped(inet->inet_rcv_saddr, &np->rcv_saddr);
Gerrit Renker73c9e022006-11-10 13:01:31 -0200945
946 return err;
947 }
948
949 if (!ipv6_addr_any(&np->rcv_saddr))
950 saddr = &np->rcv_saddr;
951
David S. Miller4c9483b2011-03-12 16:22:43 -0500952 fl6.flowi6_proto = IPPROTO_DCCP;
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +0000953 fl6.daddr = np->daddr;
954 fl6.saddr = saddr ? *saddr : np->saddr;
David S. Miller4c9483b2011-03-12 16:22:43 -0500955 fl6.flowi6_oif = sk->sk_bound_dev_if;
David S. Miller1958b852011-03-12 16:36:19 -0500956 fl6.fl6_dport = usin->sin6_port;
957 fl6.fl6_sport = inet->inet_sport;
David S. Miller4c9483b2011-03-12 16:22:43 -0500958 security_sk_classify_flow(sk, flowi6_to_flowi(&fl6));
Gerrit Renker73c9e022006-11-10 13:01:31 -0200959
David S. Miller4c9483b2011-03-12 16:22:43 -0500960 final_p = fl6_update_dst(&fl6, np->opt, &final);
Gerrit Renker73c9e022006-11-10 13:01:31 -0200961
David S. Miller4c9483b2011-03-12 16:22:43 -0500962 dst = ip6_dst_lookup_flow(sk, &fl6, final_p, true);
David S. Miller68d0c6d2011-03-01 13:19:07 -0800963 if (IS_ERR(dst)) {
964 err = PTR_ERR(dst);
Gerrit Renker73c9e022006-11-10 13:01:31 -0200965 goto failure;
David S. Miller14e50e52007-05-24 18:17:54 -0700966 }
Gerrit Renker73c9e022006-11-10 13:01:31 -0200967
968 if (saddr == NULL) {
David S. Miller4c9483b2011-03-12 16:22:43 -0500969 saddr = &fl6.saddr;
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +0000970 np->rcv_saddr = *saddr;
Gerrit Renker73c9e022006-11-10 13:01:31 -0200971 }
972
973 /* set the source address */
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +0000974 np->saddr = *saddr;
Eric Dumazetc720c7e2009-10-15 06:30:45 +0000975 inet->inet_rcv_saddr = LOOPBACK4_IPV6;
Gerrit Renker73c9e022006-11-10 13:01:31 -0200976
977 __ip6_dst_store(sk, dst, NULL, NULL);
978
979 icsk->icsk_ext_hdr_len = 0;
980 if (np->opt != NULL)
981 icsk->icsk_ext_hdr_len = (np->opt->opt_flen +
982 np->opt->opt_nflen);
983
Eric Dumazetc720c7e2009-10-15 06:30:45 +0000984 inet->inet_dport = usin->sin6_port;
Gerrit Renker73c9e022006-11-10 13:01:31 -0200985
986 dccp_set_state(sk, DCCP_REQUESTING);
987 err = inet6_hash_connect(&dccp_death_row, sk);
988 if (err)
989 goto late_failure;
Gerrit Renkerd7f73652006-11-13 13:34:38 -0200990
991 dp->dccps_iss = secure_dccpv6_sequence_number(np->saddr.s6_addr32,
992 np->daddr.s6_addr32,
Eric Dumazetc720c7e2009-10-15 06:30:45 +0000993 inet->inet_sport,
994 inet->inet_dport);
Gerrit Renker73c9e022006-11-10 13:01:31 -0200995 err = dccp_connect(sk);
996 if (err)
997 goto late_failure;
998
999 return 0;
1000
1001late_failure:
1002 dccp_set_state(sk, DCCP_CLOSED);
1003 __sk_dst_reset(sk);
1004failure:
Eric Dumazetc720c7e2009-10-15 06:30:45 +00001005 inet->inet_dport = 0;
Gerrit Renker73c9e022006-11-10 13:01:31 -02001006 sk->sk_route_caps = 0;
1007 return err;
1008}
1009
Stephen Hemminger3b401a82009-09-01 19:25:04 +00001010static const struct inet_connection_sock_af_ops dccp_ipv6_af_ops = {
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001011 .queue_xmit = inet6_csk_xmit,
1012 .send_check = dccp_v6_send_check,
1013 .rebuild_header = inet6_sk_rebuild_header,
1014 .conn_request = dccp_v6_conn_request,
1015 .syn_recv_sock = dccp_v6_request_recv_sock,
1016 .net_header_len = sizeof(struct ipv6hdr),
1017 .setsockopt = ipv6_setsockopt,
1018 .getsockopt = ipv6_getsockopt,
1019 .addr2sockaddr = inet6_csk_addr2sockaddr,
1020 .sockaddr_len = sizeof(struct sockaddr_in6),
Arnaldo Carvalho de Meloab1e0a12008-02-03 04:06:04 -08001021 .bind_conflict = inet6_csk_bind_conflict,
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001022#ifdef CONFIG_COMPAT
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001023 .compat_setsockopt = compat_ipv6_setsockopt,
1024 .compat_getsockopt = compat_ipv6_getsockopt,
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001025#endif
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001026};
1027
1028/*
1029 * DCCP over IPv4 via INET6 API
1030 */
Stephen Hemminger3b401a82009-09-01 19:25:04 +00001031static const struct inet_connection_sock_af_ops dccp_ipv6_mapped = {
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001032 .queue_xmit = ip_queue_xmit,
1033 .send_check = dccp_v4_send_check,
1034 .rebuild_header = inet_sk_rebuild_header,
1035 .conn_request = dccp_v6_conn_request,
1036 .syn_recv_sock = dccp_v6_request_recv_sock,
1037 .net_header_len = sizeof(struct iphdr),
1038 .setsockopt = ipv6_setsockopt,
1039 .getsockopt = ipv6_getsockopt,
1040 .addr2sockaddr = inet6_csk_addr2sockaddr,
1041 .sockaddr_len = sizeof(struct sockaddr_in6),
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001042#ifdef CONFIG_COMPAT
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001043 .compat_setsockopt = compat_ipv6_setsockopt,
1044 .compat_getsockopt = compat_ipv6_getsockopt,
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001045#endif
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001046};
1047
1048/* NOTE: A lot of things set to zero explicitly by call to
1049 * sk_alloc() so need not be done here.
1050 */
1051static int dccp_v6_init_sock(struct sock *sk)
1052{
Arnaldo Carvalho de Melo72478872006-03-20 22:00:37 -08001053 static __u8 dccp_v6_ctl_sock_initialized;
1054 int err = dccp_init_sock(sk, dccp_v6_ctl_sock_initialized);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001055
Arnaldo Carvalho de Melo72478872006-03-20 22:00:37 -08001056 if (err == 0) {
1057 if (unlikely(!dccp_v6_ctl_sock_initialized))
1058 dccp_v6_ctl_sock_initialized = 1;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001059 inet_csk(sk)->icsk_af_ops = &dccp_ipv6_af_ops;
Arnaldo Carvalho de Melo72478872006-03-20 22:00:37 -08001060 }
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001061
1062 return err;
1063}
1064
Brian Haley7d06b2e2008-06-14 17:04:49 -07001065static void dccp_v6_destroy_sock(struct sock *sk)
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001066{
Arnaldo Carvalho de Melo3e0fadc2006-03-20 21:23:15 -08001067 dccp_destroy_sock(sk);
Brian Haley7d06b2e2008-06-14 17:04:49 -07001068 inet6_destroy_sock(sk);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001069}
1070
Gerrit Renker73c9e022006-11-10 13:01:31 -02001071static struct timewait_sock_ops dccp6_timewait_sock_ops = {
1072 .twsk_obj_size = sizeof(struct dccp6_timewait_sock),
1073};
1074
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001075static struct proto dccp_v6_prot = {
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001076 .name = "DCCPv6",
1077 .owner = THIS_MODULE,
1078 .close = dccp_close,
1079 .connect = dccp_v6_connect,
1080 .disconnect = dccp_disconnect,
1081 .ioctl = dccp_ioctl,
1082 .init = dccp_v6_init_sock,
1083 .setsockopt = dccp_setsockopt,
1084 .getsockopt = dccp_getsockopt,
1085 .sendmsg = dccp_sendmsg,
1086 .recvmsg = dccp_recvmsg,
1087 .backlog_rcv = dccp_v6_do_rcv,
1088 .hash = dccp_v6_hash,
Arnaldo Carvalho de Meloab1e0a12008-02-03 04:06:04 -08001089 .unhash = inet_unhash,
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001090 .accept = inet_csk_accept,
Arnaldo Carvalho de Meloab1e0a12008-02-03 04:06:04 -08001091 .get_port = inet_csk_get_port,
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001092 .shutdown = dccp_shutdown,
1093 .destroy = dccp_v6_destroy_sock,
1094 .orphan_count = &dccp_orphan_count,
1095 .max_header = MAX_DCCP_HEADER,
1096 .obj_size = sizeof(struct dccp6_sock),
Eric Dumazet3ab5aee2008-11-16 19:40:17 -08001097 .slab_flags = SLAB_DESTROY_BY_RCU,
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001098 .rsk_prot = &dccp6_request_sock_ops,
1099 .twsk_prot = &dccp6_timewait_sock_ops,
Pavel Emelyanov39d8cda2008-03-22 16:50:58 -07001100 .h.hashinfo = &dccp_hashinfo,
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001101#ifdef CONFIG_COMPAT
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001102 .compat_setsockopt = compat_dccp_setsockopt,
1103 .compat_getsockopt = compat_dccp_getsockopt,
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001104#endif
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001105};
1106
Alexey Dobriyan41135cc2009-09-14 12:22:28 +00001107static const struct inet6_protocol dccp_v6_protocol = {
Arnaldo Carvalho de Melo45329e72006-03-20 22:01:29 -08001108 .handler = dccp_v6_rcv,
1109 .err_handler = dccp_v6_err,
1110 .flags = INET6_PROTO_NOPOLICY | INET6_PROTO_FINAL,
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001111};
1112
Alexey Dobriyan5708e862009-09-14 12:23:23 +00001113static const struct proto_ops inet6_dccp_ops = {
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001114 .family = PF_INET6,
1115 .owner = THIS_MODULE,
1116 .release = inet6_release,
1117 .bind = inet6_bind,
1118 .connect = inet_stream_connect,
1119 .socketpair = sock_no_socketpair,
1120 .accept = inet_accept,
1121 .getname = inet6_getname,
1122 .poll = dccp_poll,
1123 .ioctl = inet6_ioctl,
1124 .listen = inet_dccp_listen,
1125 .shutdown = inet_shutdown,
1126 .setsockopt = sock_common_setsockopt,
1127 .getsockopt = sock_common_getsockopt,
1128 .sendmsg = inet_sendmsg,
1129 .recvmsg = sock_common_recvmsg,
1130 .mmap = sock_no_mmap,
1131 .sendpage = sock_no_sendpage,
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001132#ifdef CONFIG_COMPAT
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001133 .compat_setsockopt = compat_sock_common_setsockopt,
1134 .compat_getsockopt = compat_sock_common_getsockopt,
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001135#endif
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001136};
1137
1138static struct inet_protosw dccp_v6_protosw = {
1139 .type = SOCK_DCCP,
1140 .protocol = IPPROTO_DCCP,
1141 .prot = &dccp_v6_prot,
1142 .ops = &inet6_dccp_ops,
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -08001143 .flags = INET_PROTOSW_ICSK,
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001144};
1145
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00001146static int __net_init dccp_v6_init_net(struct net *net)
Pavel Emelyanov8231bd22008-04-13 22:32:02 -07001147{
Gerrit Renkerd14a0eb2010-03-14 20:13:19 +00001148 if (dccp_hashinfo.bhash == NULL)
1149 return -ESOCKTNOSUPPORT;
Pavel Emelyanov334527d2008-04-13 22:32:45 -07001150
Gerrit Renkerd14a0eb2010-03-14 20:13:19 +00001151 return inet_ctl_sock_create(&net->dccp.v6_ctl_sk, PF_INET6,
1152 SOCK_DCCP, IPPROTO_DCCP, net);
Pavel Emelyanov8231bd22008-04-13 22:32:02 -07001153}
1154
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00001155static void __net_exit dccp_v6_exit_net(struct net *net)
Pavel Emelyanov8231bd22008-04-13 22:32:02 -07001156{
Pavel Emelyanov334527d2008-04-13 22:32:45 -07001157 inet_ctl_sock_destroy(net->dccp.v6_ctl_sk);
Pavel Emelyanov8231bd22008-04-13 22:32:02 -07001158}
1159
1160static struct pernet_operations dccp_v6_ops = {
1161 .init = dccp_v6_init_net,
1162 .exit = dccp_v6_exit_net,
1163};
1164
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001165static int __init dccp_v6_init(void)
1166{
1167 int err = proto_register(&dccp_v6_prot, 1);
1168
1169 if (err != 0)
1170 goto out;
1171
1172 err = inet6_add_protocol(&dccp_v6_protocol, IPPROTO_DCCP);
1173 if (err != 0)
1174 goto out_unregister_proto;
1175
1176 inet6_register_protosw(&dccp_v6_protosw);
Arnaldo Carvalho de Melo72478872006-03-20 22:00:37 -08001177
Pavel Emelyanov8231bd22008-04-13 22:32:02 -07001178 err = register_pernet_subsys(&dccp_v6_ops);
1179 if (err != 0)
1180 goto out_destroy_ctl_sock;
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001181out:
1182 return err;
Pavel Emelyanov8231bd22008-04-13 22:32:02 -07001183
1184out_destroy_ctl_sock:
Arnaldo Carvalho de Melo72478872006-03-20 22:00:37 -08001185 inet6_del_protocol(&dccp_v6_protocol, IPPROTO_DCCP);
1186 inet6_unregister_protosw(&dccp_v6_protosw);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001187out_unregister_proto:
1188 proto_unregister(&dccp_v6_prot);
1189 goto out;
1190}
1191
1192static void __exit dccp_v6_exit(void)
1193{
Pavel Emelyanov8231bd22008-04-13 22:32:02 -07001194 unregister_pernet_subsys(&dccp_v6_ops);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001195 inet6_del_protocol(&dccp_v6_protocol, IPPROTO_DCCP);
1196 inet6_unregister_protosw(&dccp_v6_protosw);
1197 proto_unregister(&dccp_v6_prot);
1198}
1199
1200module_init(dccp_v6_init);
1201module_exit(dccp_v6_exit);
1202
1203/*
1204 * __stringify doesn't likes enums, so use SOCK_DCCP (6) and IPPROTO_DCCP (33)
1205 * values directly, Also cover the case where the protocol is not specified,
1206 * i.e. net-pf-PF_INET6-proto-0-type-SOCK_DCCP
1207 */
Jean Delvare7131c6c2007-10-21 16:45:03 -07001208MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_INET6, 33, 6);
1209MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_INET6, 0, 6);
Arnaldo Carvalho de Melo3df80d92005-12-13 23:24:53 -08001210MODULE_LICENSE("GPL");
1211MODULE_AUTHOR("Arnaldo Carvalho de Melo <acme@mandriva.com>");
1212MODULE_DESCRIPTION("DCCPv6 - Datagram Congestion Controlled Protocol");