1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * DCCP over IPv6
4*4882a593Smuzhiyun * Linux INET6 implementation
5*4882a593Smuzhiyun *
6*4882a593Smuzhiyun * Based on net/dccp6/ipv6.c
7*4882a593Smuzhiyun *
8*4882a593Smuzhiyun * Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
9*4882a593Smuzhiyun */
10*4882a593Smuzhiyun
11*4882a593Smuzhiyun #include <linux/module.h>
12*4882a593Smuzhiyun #include <linux/random.h>
13*4882a593Smuzhiyun #include <linux/slab.h>
14*4882a593Smuzhiyun #include <linux/xfrm.h>
15*4882a593Smuzhiyun #include <linux/string.h>
16*4882a593Smuzhiyun
17*4882a593Smuzhiyun #include <net/addrconf.h>
18*4882a593Smuzhiyun #include <net/inet_common.h>
19*4882a593Smuzhiyun #include <net/inet_hashtables.h>
20*4882a593Smuzhiyun #include <net/inet_sock.h>
21*4882a593Smuzhiyun #include <net/inet6_connection_sock.h>
22*4882a593Smuzhiyun #include <net/inet6_hashtables.h>
23*4882a593Smuzhiyun #include <net/ip6_route.h>
24*4882a593Smuzhiyun #include <net/ipv6.h>
25*4882a593Smuzhiyun #include <net/protocol.h>
26*4882a593Smuzhiyun #include <net/transp_v6.h>
27*4882a593Smuzhiyun #include <net/ip6_checksum.h>
28*4882a593Smuzhiyun #include <net/xfrm.h>
29*4882a593Smuzhiyun #include <net/secure_seq.h>
30*4882a593Smuzhiyun #include <net/sock.h>
31*4882a593Smuzhiyun
32*4882a593Smuzhiyun #include "dccp.h"
33*4882a593Smuzhiyun #include "ipv6.h"
34*4882a593Smuzhiyun #include "feat.h"
35*4882a593Smuzhiyun
36*4882a593Smuzhiyun /* The per-net dccp.v6_ctl_sk is used for sending RSTs and ACKs */
37*4882a593Smuzhiyun
38*4882a593Smuzhiyun static const struct inet_connection_sock_af_ops dccp_ipv6_mapped;
39*4882a593Smuzhiyun static const struct inet_connection_sock_af_ops dccp_ipv6_af_ops;
40*4882a593Smuzhiyun
41*4882a593Smuzhiyun /* add pseudo-header to DCCP checksum stored in skb->csum */
dccp_v6_csum_finish(struct sk_buff * skb,const struct in6_addr * saddr,const struct in6_addr * daddr)42*4882a593Smuzhiyun static inline __sum16 dccp_v6_csum_finish(struct sk_buff *skb,
43*4882a593Smuzhiyun const struct in6_addr *saddr,
44*4882a593Smuzhiyun const struct in6_addr *daddr)
45*4882a593Smuzhiyun {
46*4882a593Smuzhiyun return csum_ipv6_magic(saddr, daddr, skb->len, IPPROTO_DCCP, skb->csum);
47*4882a593Smuzhiyun }
48*4882a593Smuzhiyun
dccp_v6_send_check(struct sock * sk,struct sk_buff * skb)49*4882a593Smuzhiyun static inline void dccp_v6_send_check(struct sock *sk, struct sk_buff *skb)
50*4882a593Smuzhiyun {
51*4882a593Smuzhiyun struct ipv6_pinfo *np = inet6_sk(sk);
52*4882a593Smuzhiyun struct dccp_hdr *dh = dccp_hdr(skb);
53*4882a593Smuzhiyun
54*4882a593Smuzhiyun dccp_csum_outgoing(skb);
55*4882a593Smuzhiyun dh->dccph_checksum = dccp_v6_csum_finish(skb, &np->saddr, &sk->sk_v6_daddr);
56*4882a593Smuzhiyun }
57*4882a593Smuzhiyun
dccp_v6_init_sequence(struct sk_buff * skb)58*4882a593Smuzhiyun static inline __u64 dccp_v6_init_sequence(struct sk_buff *skb)
59*4882a593Smuzhiyun {
60*4882a593Smuzhiyun return secure_dccpv6_sequence_number(ipv6_hdr(skb)->daddr.s6_addr32,
61*4882a593Smuzhiyun ipv6_hdr(skb)->saddr.s6_addr32,
62*4882a593Smuzhiyun dccp_hdr(skb)->dccph_dport,
63*4882a593Smuzhiyun dccp_hdr(skb)->dccph_sport );
64*4882a593Smuzhiyun
65*4882a593Smuzhiyun }
66*4882a593Smuzhiyun
dccp_v6_err(struct sk_buff * skb,struct inet6_skb_parm * opt,u8 type,u8 code,int offset,__be32 info)67*4882a593Smuzhiyun static int dccp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
68*4882a593Smuzhiyun u8 type, u8 code, int offset, __be32 info)
69*4882a593Smuzhiyun {
70*4882a593Smuzhiyun const struct ipv6hdr *hdr = (const struct ipv6hdr *)skb->data;
71*4882a593Smuzhiyun const struct dccp_hdr *dh;
72*4882a593Smuzhiyun struct dccp_sock *dp;
73*4882a593Smuzhiyun struct ipv6_pinfo *np;
74*4882a593Smuzhiyun struct sock *sk;
75*4882a593Smuzhiyun int err;
76*4882a593Smuzhiyun __u64 seq;
77*4882a593Smuzhiyun struct net *net = dev_net(skb->dev);
78*4882a593Smuzhiyun
79*4882a593Smuzhiyun /* Only need dccph_dport & dccph_sport which are the first
80*4882a593Smuzhiyun * 4 bytes in dccp header.
81*4882a593Smuzhiyun * Our caller (icmpv6_notify()) already pulled 8 bytes for us.
82*4882a593Smuzhiyun */
83*4882a593Smuzhiyun BUILD_BUG_ON(offsetofend(struct dccp_hdr, dccph_sport) > 8);
84*4882a593Smuzhiyun BUILD_BUG_ON(offsetofend(struct dccp_hdr, dccph_dport) > 8);
85*4882a593Smuzhiyun dh = (struct dccp_hdr *)(skb->data + offset);
86*4882a593Smuzhiyun
87*4882a593Smuzhiyun sk = __inet6_lookup_established(net, &dccp_hashinfo,
88*4882a593Smuzhiyun &hdr->daddr, dh->dccph_dport,
89*4882a593Smuzhiyun &hdr->saddr, ntohs(dh->dccph_sport),
90*4882a593Smuzhiyun inet6_iif(skb), 0);
91*4882a593Smuzhiyun
92*4882a593Smuzhiyun if (!sk) {
93*4882a593Smuzhiyun __ICMP6_INC_STATS(net, __in6_dev_get(skb->dev),
94*4882a593Smuzhiyun ICMP6_MIB_INERRORS);
95*4882a593Smuzhiyun return -ENOENT;
96*4882a593Smuzhiyun }
97*4882a593Smuzhiyun
98*4882a593Smuzhiyun if (sk->sk_state == DCCP_TIME_WAIT) {
99*4882a593Smuzhiyun inet_twsk_put(inet_twsk(sk));
100*4882a593Smuzhiyun return 0;
101*4882a593Smuzhiyun }
102*4882a593Smuzhiyun seq = dccp_hdr_seq(dh);
103*4882a593Smuzhiyun if (sk->sk_state == DCCP_NEW_SYN_RECV) {
104*4882a593Smuzhiyun dccp_req_err(sk, seq);
105*4882a593Smuzhiyun return 0;
106*4882a593Smuzhiyun }
107*4882a593Smuzhiyun
108*4882a593Smuzhiyun bh_lock_sock(sk);
109*4882a593Smuzhiyun if (sock_owned_by_user(sk))
110*4882a593Smuzhiyun __NET_INC_STATS(net, LINUX_MIB_LOCKDROPPEDICMPS);
111*4882a593Smuzhiyun
112*4882a593Smuzhiyun if (sk->sk_state == DCCP_CLOSED)
113*4882a593Smuzhiyun goto out;
114*4882a593Smuzhiyun
115*4882a593Smuzhiyun dp = dccp_sk(sk);
116*4882a593Smuzhiyun if ((1 << sk->sk_state) & ~(DCCPF_REQUESTING | DCCPF_LISTEN) &&
117*4882a593Smuzhiyun !between48(seq, dp->dccps_awl, dp->dccps_awh)) {
118*4882a593Smuzhiyun __NET_INC_STATS(net, LINUX_MIB_OUTOFWINDOWICMPS);
119*4882a593Smuzhiyun goto out;
120*4882a593Smuzhiyun }
121*4882a593Smuzhiyun
122*4882a593Smuzhiyun np = inet6_sk(sk);
123*4882a593Smuzhiyun
124*4882a593Smuzhiyun if (type == NDISC_REDIRECT) {
125*4882a593Smuzhiyun if (!sock_owned_by_user(sk)) {
126*4882a593Smuzhiyun struct dst_entry *dst = __sk_dst_check(sk, np->dst_cookie);
127*4882a593Smuzhiyun
128*4882a593Smuzhiyun if (dst)
129*4882a593Smuzhiyun dst->ops->redirect(dst, sk, skb);
130*4882a593Smuzhiyun }
131*4882a593Smuzhiyun goto out;
132*4882a593Smuzhiyun }
133*4882a593Smuzhiyun
134*4882a593Smuzhiyun if (type == ICMPV6_PKT_TOOBIG) {
135*4882a593Smuzhiyun struct dst_entry *dst = NULL;
136*4882a593Smuzhiyun
137*4882a593Smuzhiyun if (!ip6_sk_accept_pmtu(sk))
138*4882a593Smuzhiyun goto out;
139*4882a593Smuzhiyun
140*4882a593Smuzhiyun if (sock_owned_by_user(sk))
141*4882a593Smuzhiyun goto out;
142*4882a593Smuzhiyun if ((1 << sk->sk_state) & (DCCPF_LISTEN | DCCPF_CLOSED))
143*4882a593Smuzhiyun goto out;
144*4882a593Smuzhiyun
145*4882a593Smuzhiyun dst = inet6_csk_update_pmtu(sk, ntohl(info));
146*4882a593Smuzhiyun if (!dst)
147*4882a593Smuzhiyun goto out;
148*4882a593Smuzhiyun
149*4882a593Smuzhiyun if (inet_csk(sk)->icsk_pmtu_cookie > dst_mtu(dst))
150*4882a593Smuzhiyun dccp_sync_mss(sk, dst_mtu(dst));
151*4882a593Smuzhiyun goto out;
152*4882a593Smuzhiyun }
153*4882a593Smuzhiyun
154*4882a593Smuzhiyun icmpv6_err_convert(type, code, &err);
155*4882a593Smuzhiyun
156*4882a593Smuzhiyun /* Might be for an request_sock */
157*4882a593Smuzhiyun switch (sk->sk_state) {
158*4882a593Smuzhiyun case DCCP_REQUESTING:
159*4882a593Smuzhiyun case DCCP_RESPOND: /* Cannot happen.
160*4882a593Smuzhiyun It can, it SYNs are crossed. --ANK */
161*4882a593Smuzhiyun if (!sock_owned_by_user(sk)) {
162*4882a593Smuzhiyun __DCCP_INC_STATS(DCCP_MIB_ATTEMPTFAILS);
163*4882a593Smuzhiyun sk->sk_err = err;
164*4882a593Smuzhiyun /*
165*4882a593Smuzhiyun * Wake people up to see the error
166*4882a593Smuzhiyun * (see connect in sock.c)
167*4882a593Smuzhiyun */
168*4882a593Smuzhiyun sk->sk_error_report(sk);
169*4882a593Smuzhiyun dccp_done(sk);
170*4882a593Smuzhiyun } else
171*4882a593Smuzhiyun sk->sk_err_soft = err;
172*4882a593Smuzhiyun goto out;
173*4882a593Smuzhiyun }
174*4882a593Smuzhiyun
175*4882a593Smuzhiyun if (!sock_owned_by_user(sk) && np->recverr) {
176*4882a593Smuzhiyun sk->sk_err = err;
177*4882a593Smuzhiyun sk->sk_error_report(sk);
178*4882a593Smuzhiyun } else
179*4882a593Smuzhiyun sk->sk_err_soft = err;
180*4882a593Smuzhiyun
181*4882a593Smuzhiyun out:
182*4882a593Smuzhiyun bh_unlock_sock(sk);
183*4882a593Smuzhiyun sock_put(sk);
184*4882a593Smuzhiyun return 0;
185*4882a593Smuzhiyun }
186*4882a593Smuzhiyun
187*4882a593Smuzhiyun
dccp_v6_send_response(const struct sock * sk,struct request_sock * req)188*4882a593Smuzhiyun static int dccp_v6_send_response(const struct sock *sk, struct request_sock *req)
189*4882a593Smuzhiyun {
190*4882a593Smuzhiyun struct inet_request_sock *ireq = inet_rsk(req);
191*4882a593Smuzhiyun struct ipv6_pinfo *np = inet6_sk(sk);
192*4882a593Smuzhiyun struct sk_buff *skb;
193*4882a593Smuzhiyun struct in6_addr *final_p, final;
194*4882a593Smuzhiyun struct flowi6 fl6;
195*4882a593Smuzhiyun int err = -1;
196*4882a593Smuzhiyun struct dst_entry *dst;
197*4882a593Smuzhiyun
198*4882a593Smuzhiyun memset(&fl6, 0, sizeof(fl6));
199*4882a593Smuzhiyun fl6.flowi6_proto = IPPROTO_DCCP;
200*4882a593Smuzhiyun fl6.daddr = ireq->ir_v6_rmt_addr;
201*4882a593Smuzhiyun fl6.saddr = ireq->ir_v6_loc_addr;
202*4882a593Smuzhiyun fl6.flowlabel = 0;
203*4882a593Smuzhiyun fl6.flowi6_oif = ireq->ir_iif;
204*4882a593Smuzhiyun fl6.fl6_dport = ireq->ir_rmt_port;
205*4882a593Smuzhiyun fl6.fl6_sport = htons(ireq->ir_num);
206*4882a593Smuzhiyun security_req_classify_flow(req, flowi6_to_flowi_common(&fl6));
207*4882a593Smuzhiyun
208*4882a593Smuzhiyun
209*4882a593Smuzhiyun rcu_read_lock();
210*4882a593Smuzhiyun final_p = fl6_update_dst(&fl6, rcu_dereference(np->opt), &final);
211*4882a593Smuzhiyun rcu_read_unlock();
212*4882a593Smuzhiyun
213*4882a593Smuzhiyun dst = ip6_dst_lookup_flow(sock_net(sk), sk, &fl6, final_p);
214*4882a593Smuzhiyun if (IS_ERR(dst)) {
215*4882a593Smuzhiyun err = PTR_ERR(dst);
216*4882a593Smuzhiyun dst = NULL;
217*4882a593Smuzhiyun goto done;
218*4882a593Smuzhiyun }
219*4882a593Smuzhiyun
220*4882a593Smuzhiyun skb = dccp_make_response(sk, dst, req);
221*4882a593Smuzhiyun if (skb != NULL) {
222*4882a593Smuzhiyun struct dccp_hdr *dh = dccp_hdr(skb);
223*4882a593Smuzhiyun struct ipv6_txoptions *opt;
224*4882a593Smuzhiyun
225*4882a593Smuzhiyun dh->dccph_checksum = dccp_v6_csum_finish(skb,
226*4882a593Smuzhiyun &ireq->ir_v6_loc_addr,
227*4882a593Smuzhiyun &ireq->ir_v6_rmt_addr);
228*4882a593Smuzhiyun fl6.daddr = ireq->ir_v6_rmt_addr;
229*4882a593Smuzhiyun rcu_read_lock();
230*4882a593Smuzhiyun opt = ireq->ipv6_opt;
231*4882a593Smuzhiyun if (!opt)
232*4882a593Smuzhiyun opt = rcu_dereference(np->opt);
233*4882a593Smuzhiyun err = ip6_xmit(sk, skb, &fl6, sk->sk_mark, opt, np->tclass,
234*4882a593Smuzhiyun sk->sk_priority);
235*4882a593Smuzhiyun rcu_read_unlock();
236*4882a593Smuzhiyun err = net_xmit_eval(err);
237*4882a593Smuzhiyun }
238*4882a593Smuzhiyun
239*4882a593Smuzhiyun done:
240*4882a593Smuzhiyun dst_release(dst);
241*4882a593Smuzhiyun return err;
242*4882a593Smuzhiyun }
243*4882a593Smuzhiyun
dccp_v6_reqsk_destructor(struct request_sock * req)244*4882a593Smuzhiyun static void dccp_v6_reqsk_destructor(struct request_sock *req)
245*4882a593Smuzhiyun {
246*4882a593Smuzhiyun dccp_feat_list_purge(&dccp_rsk(req)->dreq_featneg);
247*4882a593Smuzhiyun kfree(inet_rsk(req)->ipv6_opt);
248*4882a593Smuzhiyun kfree_skb(inet_rsk(req)->pktopts);
249*4882a593Smuzhiyun }
250*4882a593Smuzhiyun
dccp_v6_ctl_send_reset(const struct sock * sk,struct sk_buff * rxskb)251*4882a593Smuzhiyun static void dccp_v6_ctl_send_reset(const struct sock *sk, struct sk_buff *rxskb)
252*4882a593Smuzhiyun {
253*4882a593Smuzhiyun const struct ipv6hdr *rxip6h;
254*4882a593Smuzhiyun struct sk_buff *skb;
255*4882a593Smuzhiyun struct flowi6 fl6;
256*4882a593Smuzhiyun struct net *net = dev_net(skb_dst(rxskb)->dev);
257*4882a593Smuzhiyun struct sock *ctl_sk = net->dccp.v6_ctl_sk;
258*4882a593Smuzhiyun struct dst_entry *dst;
259*4882a593Smuzhiyun
260*4882a593Smuzhiyun if (dccp_hdr(rxskb)->dccph_type == DCCP_PKT_RESET)
261*4882a593Smuzhiyun return;
262*4882a593Smuzhiyun
263*4882a593Smuzhiyun if (!ipv6_unicast_destination(rxskb))
264*4882a593Smuzhiyun return;
265*4882a593Smuzhiyun
266*4882a593Smuzhiyun skb = dccp_ctl_make_reset(ctl_sk, rxskb);
267*4882a593Smuzhiyun if (skb == NULL)
268*4882a593Smuzhiyun return;
269*4882a593Smuzhiyun
270*4882a593Smuzhiyun rxip6h = ipv6_hdr(rxskb);
271*4882a593Smuzhiyun dccp_hdr(skb)->dccph_checksum = dccp_v6_csum_finish(skb, &rxip6h->saddr,
272*4882a593Smuzhiyun &rxip6h->daddr);
273*4882a593Smuzhiyun
274*4882a593Smuzhiyun memset(&fl6, 0, sizeof(fl6));
275*4882a593Smuzhiyun fl6.daddr = rxip6h->saddr;
276*4882a593Smuzhiyun fl6.saddr = rxip6h->daddr;
277*4882a593Smuzhiyun
278*4882a593Smuzhiyun fl6.flowi6_proto = IPPROTO_DCCP;
279*4882a593Smuzhiyun fl6.flowi6_oif = inet6_iif(rxskb);
280*4882a593Smuzhiyun fl6.fl6_dport = dccp_hdr(skb)->dccph_dport;
281*4882a593Smuzhiyun fl6.fl6_sport = dccp_hdr(skb)->dccph_sport;
282*4882a593Smuzhiyun security_skb_classify_flow(rxskb, flowi6_to_flowi_common(&fl6));
283*4882a593Smuzhiyun
284*4882a593Smuzhiyun /* sk = NULL, but it is safe for now. RST socket required. */
285*4882a593Smuzhiyun dst = ip6_dst_lookup_flow(sock_net(ctl_sk), ctl_sk, &fl6, NULL);
286*4882a593Smuzhiyun if (!IS_ERR(dst)) {
287*4882a593Smuzhiyun skb_dst_set(skb, dst);
288*4882a593Smuzhiyun ip6_xmit(ctl_sk, skb, &fl6, 0, NULL, 0, 0);
289*4882a593Smuzhiyun DCCP_INC_STATS(DCCP_MIB_OUTSEGS);
290*4882a593Smuzhiyun DCCP_INC_STATS(DCCP_MIB_OUTRSTS);
291*4882a593Smuzhiyun return;
292*4882a593Smuzhiyun }
293*4882a593Smuzhiyun
294*4882a593Smuzhiyun kfree_skb(skb);
295*4882a593Smuzhiyun }
296*4882a593Smuzhiyun
297*4882a593Smuzhiyun static struct request_sock_ops dccp6_request_sock_ops = {
298*4882a593Smuzhiyun .family = AF_INET6,
299*4882a593Smuzhiyun .obj_size = sizeof(struct dccp6_request_sock),
300*4882a593Smuzhiyun .rtx_syn_ack = dccp_v6_send_response,
301*4882a593Smuzhiyun .send_ack = dccp_reqsk_send_ack,
302*4882a593Smuzhiyun .destructor = dccp_v6_reqsk_destructor,
303*4882a593Smuzhiyun .send_reset = dccp_v6_ctl_send_reset,
304*4882a593Smuzhiyun .syn_ack_timeout = dccp_syn_ack_timeout,
305*4882a593Smuzhiyun };
306*4882a593Smuzhiyun
dccp_v6_conn_request(struct sock * sk,struct sk_buff * skb)307*4882a593Smuzhiyun static int dccp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
308*4882a593Smuzhiyun {
309*4882a593Smuzhiyun struct request_sock *req;
310*4882a593Smuzhiyun struct dccp_request_sock *dreq;
311*4882a593Smuzhiyun struct inet_request_sock *ireq;
312*4882a593Smuzhiyun struct ipv6_pinfo *np = inet6_sk(sk);
313*4882a593Smuzhiyun const __be32 service = dccp_hdr_request(skb)->dccph_req_service;
314*4882a593Smuzhiyun struct dccp_skb_cb *dcb = DCCP_SKB_CB(skb);
315*4882a593Smuzhiyun
316*4882a593Smuzhiyun if (skb->protocol == htons(ETH_P_IP))
317*4882a593Smuzhiyun return dccp_v4_conn_request(sk, skb);
318*4882a593Smuzhiyun
319*4882a593Smuzhiyun if (!ipv6_unicast_destination(skb))
320*4882a593Smuzhiyun return 0; /* discard, don't send a reset here */
321*4882a593Smuzhiyun
322*4882a593Smuzhiyun if (ipv6_addr_v4mapped(&ipv6_hdr(skb)->saddr)) {
323*4882a593Smuzhiyun __IP6_INC_STATS(sock_net(sk), NULL, IPSTATS_MIB_INHDRERRORS);
324*4882a593Smuzhiyun return 0;
325*4882a593Smuzhiyun }
326*4882a593Smuzhiyun
327*4882a593Smuzhiyun if (dccp_bad_service_code(sk, service)) {
328*4882a593Smuzhiyun dcb->dccpd_reset_code = DCCP_RESET_CODE_BAD_SERVICE_CODE;
329*4882a593Smuzhiyun goto drop;
330*4882a593Smuzhiyun }
331*4882a593Smuzhiyun /*
332*4882a593Smuzhiyun * There are no SYN attacks on IPv6, yet...
333*4882a593Smuzhiyun */
334*4882a593Smuzhiyun dcb->dccpd_reset_code = DCCP_RESET_CODE_TOO_BUSY;
335*4882a593Smuzhiyun if (inet_csk_reqsk_queue_is_full(sk))
336*4882a593Smuzhiyun goto drop;
337*4882a593Smuzhiyun
338*4882a593Smuzhiyun if (sk_acceptq_is_full(sk))
339*4882a593Smuzhiyun goto drop;
340*4882a593Smuzhiyun
341*4882a593Smuzhiyun req = inet_reqsk_alloc(&dccp6_request_sock_ops, sk, true);
342*4882a593Smuzhiyun if (req == NULL)
343*4882a593Smuzhiyun goto drop;
344*4882a593Smuzhiyun
345*4882a593Smuzhiyun if (dccp_reqsk_init(req, dccp_sk(sk), skb))
346*4882a593Smuzhiyun goto drop_and_free;
347*4882a593Smuzhiyun
348*4882a593Smuzhiyun dreq = dccp_rsk(req);
349*4882a593Smuzhiyun if (dccp_parse_options(sk, dreq, skb))
350*4882a593Smuzhiyun goto drop_and_free;
351*4882a593Smuzhiyun
352*4882a593Smuzhiyun if (security_inet_conn_request(sk, skb, req))
353*4882a593Smuzhiyun goto drop_and_free;
354*4882a593Smuzhiyun
355*4882a593Smuzhiyun ireq = inet_rsk(req);
356*4882a593Smuzhiyun ireq->ir_v6_rmt_addr = ipv6_hdr(skb)->saddr;
357*4882a593Smuzhiyun ireq->ir_v6_loc_addr = ipv6_hdr(skb)->daddr;
358*4882a593Smuzhiyun ireq->ireq_family = AF_INET6;
359*4882a593Smuzhiyun ireq->ir_mark = inet_request_mark(sk, skb);
360*4882a593Smuzhiyun
361*4882a593Smuzhiyun if (ipv6_opt_accepted(sk, skb, IP6CB(skb)) ||
362*4882a593Smuzhiyun np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo ||
363*4882a593Smuzhiyun np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim) {
364*4882a593Smuzhiyun refcount_inc(&skb->users);
365*4882a593Smuzhiyun ireq->pktopts = skb;
366*4882a593Smuzhiyun }
367*4882a593Smuzhiyun ireq->ir_iif = sk->sk_bound_dev_if;
368*4882a593Smuzhiyun
369*4882a593Smuzhiyun /* So that link locals have meaning */
370*4882a593Smuzhiyun if (!sk->sk_bound_dev_if &&
371*4882a593Smuzhiyun ipv6_addr_type(&ireq->ir_v6_rmt_addr) & IPV6_ADDR_LINKLOCAL)
372*4882a593Smuzhiyun ireq->ir_iif = inet6_iif(skb);
373*4882a593Smuzhiyun
374*4882a593Smuzhiyun /*
375*4882a593Smuzhiyun * Step 3: Process LISTEN state
376*4882a593Smuzhiyun *
377*4882a593Smuzhiyun * Set S.ISR, S.GSR, S.SWL, S.SWH from packet or Init Cookie
378*4882a593Smuzhiyun *
379*4882a593Smuzhiyun * Setting S.SWL/S.SWH to is deferred to dccp_create_openreq_child().
380*4882a593Smuzhiyun */
381*4882a593Smuzhiyun dreq->dreq_isr = dcb->dccpd_seq;
382*4882a593Smuzhiyun dreq->dreq_gsr = dreq->dreq_isr;
383*4882a593Smuzhiyun dreq->dreq_iss = dccp_v6_init_sequence(skb);
384*4882a593Smuzhiyun dreq->dreq_gss = dreq->dreq_iss;
385*4882a593Smuzhiyun dreq->dreq_service = service;
386*4882a593Smuzhiyun
387*4882a593Smuzhiyun if (dccp_v6_send_response(sk, req))
388*4882a593Smuzhiyun goto drop_and_free;
389*4882a593Smuzhiyun
390*4882a593Smuzhiyun inet_csk_reqsk_queue_hash_add(sk, req, DCCP_TIMEOUT_INIT);
391*4882a593Smuzhiyun reqsk_put(req);
392*4882a593Smuzhiyun return 0;
393*4882a593Smuzhiyun
394*4882a593Smuzhiyun drop_and_free:
395*4882a593Smuzhiyun reqsk_free(req);
396*4882a593Smuzhiyun drop:
397*4882a593Smuzhiyun __DCCP_INC_STATS(DCCP_MIB_ATTEMPTFAILS);
398*4882a593Smuzhiyun return -1;
399*4882a593Smuzhiyun }
400*4882a593Smuzhiyun
dccp_v6_request_recv_sock(const struct sock * sk,struct sk_buff * skb,struct request_sock * req,struct dst_entry * dst,struct request_sock * req_unhash,bool * own_req)401*4882a593Smuzhiyun static struct sock *dccp_v6_request_recv_sock(const struct sock *sk,
402*4882a593Smuzhiyun struct sk_buff *skb,
403*4882a593Smuzhiyun struct request_sock *req,
404*4882a593Smuzhiyun struct dst_entry *dst,
405*4882a593Smuzhiyun struct request_sock *req_unhash,
406*4882a593Smuzhiyun bool *own_req)
407*4882a593Smuzhiyun {
408*4882a593Smuzhiyun struct inet_request_sock *ireq = inet_rsk(req);
409*4882a593Smuzhiyun struct ipv6_pinfo *newnp;
410*4882a593Smuzhiyun const struct ipv6_pinfo *np = inet6_sk(sk);
411*4882a593Smuzhiyun struct ipv6_txoptions *opt;
412*4882a593Smuzhiyun struct inet_sock *newinet;
413*4882a593Smuzhiyun struct dccp6_sock *newdp6;
414*4882a593Smuzhiyun struct sock *newsk;
415*4882a593Smuzhiyun
416*4882a593Smuzhiyun if (skb->protocol == htons(ETH_P_IP)) {
417*4882a593Smuzhiyun /*
418*4882a593Smuzhiyun * v6 mapped
419*4882a593Smuzhiyun */
420*4882a593Smuzhiyun newsk = dccp_v4_request_recv_sock(sk, skb, req, dst,
421*4882a593Smuzhiyun req_unhash, own_req);
422*4882a593Smuzhiyun if (newsk == NULL)
423*4882a593Smuzhiyun return NULL;
424*4882a593Smuzhiyun
425*4882a593Smuzhiyun newdp6 = (struct dccp6_sock *)newsk;
426*4882a593Smuzhiyun newinet = inet_sk(newsk);
427*4882a593Smuzhiyun newinet->pinet6 = &newdp6->inet6;
428*4882a593Smuzhiyun newnp = inet6_sk(newsk);
429*4882a593Smuzhiyun
430*4882a593Smuzhiyun memcpy(newnp, np, sizeof(struct ipv6_pinfo));
431*4882a593Smuzhiyun
432*4882a593Smuzhiyun newnp->saddr = newsk->sk_v6_rcv_saddr;
433*4882a593Smuzhiyun
434*4882a593Smuzhiyun inet_csk(newsk)->icsk_af_ops = &dccp_ipv6_mapped;
435*4882a593Smuzhiyun newsk->sk_backlog_rcv = dccp_v4_do_rcv;
436*4882a593Smuzhiyun newnp->pktoptions = NULL;
437*4882a593Smuzhiyun newnp->opt = NULL;
438*4882a593Smuzhiyun newnp->ipv6_mc_list = NULL;
439*4882a593Smuzhiyun newnp->ipv6_ac_list = NULL;
440*4882a593Smuzhiyun newnp->ipv6_fl_list = NULL;
441*4882a593Smuzhiyun newnp->mcast_oif = inet_iif(skb);
442*4882a593Smuzhiyun newnp->mcast_hops = ip_hdr(skb)->ttl;
443*4882a593Smuzhiyun
444*4882a593Smuzhiyun /*
445*4882a593Smuzhiyun * No need to charge this sock to the relevant IPv6 refcnt debug socks count
446*4882a593Smuzhiyun * here, dccp_create_openreq_child now does this for us, see the comment in
447*4882a593Smuzhiyun * that function for the gory details. -acme
448*4882a593Smuzhiyun */
449*4882a593Smuzhiyun
450*4882a593Smuzhiyun /* It is tricky place. Until this moment IPv4 tcp
451*4882a593Smuzhiyun worked with IPv6 icsk.icsk_af_ops.
452*4882a593Smuzhiyun Sync it now.
453*4882a593Smuzhiyun */
454*4882a593Smuzhiyun dccp_sync_mss(newsk, inet_csk(newsk)->icsk_pmtu_cookie);
455*4882a593Smuzhiyun
456*4882a593Smuzhiyun return newsk;
457*4882a593Smuzhiyun }
458*4882a593Smuzhiyun
459*4882a593Smuzhiyun
460*4882a593Smuzhiyun if (sk_acceptq_is_full(sk))
461*4882a593Smuzhiyun goto out_overflow;
462*4882a593Smuzhiyun
463*4882a593Smuzhiyun if (!dst) {
464*4882a593Smuzhiyun struct flowi6 fl6;
465*4882a593Smuzhiyun
466*4882a593Smuzhiyun dst = inet6_csk_route_req(sk, &fl6, req, IPPROTO_DCCP);
467*4882a593Smuzhiyun if (!dst)
468*4882a593Smuzhiyun goto out;
469*4882a593Smuzhiyun }
470*4882a593Smuzhiyun
471*4882a593Smuzhiyun newsk = dccp_create_openreq_child(sk, req, skb);
472*4882a593Smuzhiyun if (newsk == NULL)
473*4882a593Smuzhiyun goto out_nonewsk;
474*4882a593Smuzhiyun
475*4882a593Smuzhiyun /*
476*4882a593Smuzhiyun * No need to charge this sock to the relevant IPv6 refcnt debug socks
477*4882a593Smuzhiyun * count here, dccp_create_openreq_child now does this for us, see the
478*4882a593Smuzhiyun * comment in that function for the gory details. -acme
479*4882a593Smuzhiyun */
480*4882a593Smuzhiyun
481*4882a593Smuzhiyun ip6_dst_store(newsk, dst, NULL, NULL);
482*4882a593Smuzhiyun newsk->sk_route_caps = dst->dev->features & ~(NETIF_F_IP_CSUM |
483*4882a593Smuzhiyun NETIF_F_TSO);
484*4882a593Smuzhiyun newdp6 = (struct dccp6_sock *)newsk;
485*4882a593Smuzhiyun newinet = inet_sk(newsk);
486*4882a593Smuzhiyun newinet->pinet6 = &newdp6->inet6;
487*4882a593Smuzhiyun newnp = inet6_sk(newsk);
488*4882a593Smuzhiyun
489*4882a593Smuzhiyun memcpy(newnp, np, sizeof(struct ipv6_pinfo));
490*4882a593Smuzhiyun
491*4882a593Smuzhiyun newsk->sk_v6_daddr = ireq->ir_v6_rmt_addr;
492*4882a593Smuzhiyun newnp->saddr = ireq->ir_v6_loc_addr;
493*4882a593Smuzhiyun newsk->sk_v6_rcv_saddr = ireq->ir_v6_loc_addr;
494*4882a593Smuzhiyun newsk->sk_bound_dev_if = ireq->ir_iif;
495*4882a593Smuzhiyun
496*4882a593Smuzhiyun /* Now IPv6 options...
497*4882a593Smuzhiyun
498*4882a593Smuzhiyun First: no IPv4 options.
499*4882a593Smuzhiyun */
500*4882a593Smuzhiyun newinet->inet_opt = NULL;
501*4882a593Smuzhiyun
502*4882a593Smuzhiyun /* Clone RX bits */
503*4882a593Smuzhiyun newnp->rxopt.all = np->rxopt.all;
504*4882a593Smuzhiyun
505*4882a593Smuzhiyun newnp->ipv6_mc_list = NULL;
506*4882a593Smuzhiyun newnp->ipv6_ac_list = NULL;
507*4882a593Smuzhiyun newnp->ipv6_fl_list = NULL;
508*4882a593Smuzhiyun newnp->pktoptions = NULL;
509*4882a593Smuzhiyun newnp->opt = NULL;
510*4882a593Smuzhiyun newnp->mcast_oif = inet6_iif(skb);
511*4882a593Smuzhiyun newnp->mcast_hops = ipv6_hdr(skb)->hop_limit;
512*4882a593Smuzhiyun
513*4882a593Smuzhiyun /*
514*4882a593Smuzhiyun * Clone native IPv6 options from listening socket (if any)
515*4882a593Smuzhiyun *
516*4882a593Smuzhiyun * Yes, keeping reference count would be much more clever, but we make
517*4882a593Smuzhiyun * one more one thing there: reattach optmem to newsk.
518*4882a593Smuzhiyun */
519*4882a593Smuzhiyun opt = ireq->ipv6_opt;
520*4882a593Smuzhiyun if (!opt)
521*4882a593Smuzhiyun opt = rcu_dereference(np->opt);
522*4882a593Smuzhiyun if (opt) {
523*4882a593Smuzhiyun opt = ipv6_dup_options(newsk, opt);
524*4882a593Smuzhiyun RCU_INIT_POINTER(newnp->opt, opt);
525*4882a593Smuzhiyun }
526*4882a593Smuzhiyun inet_csk(newsk)->icsk_ext_hdr_len = 0;
527*4882a593Smuzhiyun if (opt)
528*4882a593Smuzhiyun inet_csk(newsk)->icsk_ext_hdr_len = opt->opt_nflen +
529*4882a593Smuzhiyun opt->opt_flen;
530*4882a593Smuzhiyun
531*4882a593Smuzhiyun dccp_sync_mss(newsk, dst_mtu(dst));
532*4882a593Smuzhiyun
533*4882a593Smuzhiyun newinet->inet_daddr = newinet->inet_saddr = LOOPBACK4_IPV6;
534*4882a593Smuzhiyun newinet->inet_rcv_saddr = LOOPBACK4_IPV6;
535*4882a593Smuzhiyun
536*4882a593Smuzhiyun if (__inet_inherit_port(sk, newsk) < 0) {
537*4882a593Smuzhiyun inet_csk_prepare_forced_close(newsk);
538*4882a593Smuzhiyun dccp_done(newsk);
539*4882a593Smuzhiyun goto out;
540*4882a593Smuzhiyun }
541*4882a593Smuzhiyun *own_req = inet_ehash_nolisten(newsk, req_to_sk(req_unhash), NULL);
542*4882a593Smuzhiyun /* Clone pktoptions received with SYN, if we own the req */
543*4882a593Smuzhiyun if (*own_req && ireq->pktopts) {
544*4882a593Smuzhiyun newnp->pktoptions = skb_clone(ireq->pktopts, GFP_ATOMIC);
545*4882a593Smuzhiyun consume_skb(ireq->pktopts);
546*4882a593Smuzhiyun ireq->pktopts = NULL;
547*4882a593Smuzhiyun if (newnp->pktoptions)
548*4882a593Smuzhiyun skb_set_owner_r(newnp->pktoptions, newsk);
549*4882a593Smuzhiyun }
550*4882a593Smuzhiyun
551*4882a593Smuzhiyun return newsk;
552*4882a593Smuzhiyun
553*4882a593Smuzhiyun out_overflow:
554*4882a593Smuzhiyun __NET_INC_STATS(sock_net(sk), LINUX_MIB_LISTENOVERFLOWS);
555*4882a593Smuzhiyun out_nonewsk:
556*4882a593Smuzhiyun dst_release(dst);
557*4882a593Smuzhiyun out:
558*4882a593Smuzhiyun __NET_INC_STATS(sock_net(sk), LINUX_MIB_LISTENDROPS);
559*4882a593Smuzhiyun return NULL;
560*4882a593Smuzhiyun }
561*4882a593Smuzhiyun
562*4882a593Smuzhiyun /* The socket must have it's spinlock held when we get
563*4882a593Smuzhiyun * here.
564*4882a593Smuzhiyun *
565*4882a593Smuzhiyun * We have a potential double-lock case here, so even when
566*4882a593Smuzhiyun * doing backlog processing we use the BH locking scheme.
567*4882a593Smuzhiyun * This is because we cannot sleep with the original spinlock
568*4882a593Smuzhiyun * held.
569*4882a593Smuzhiyun */
dccp_v6_do_rcv(struct sock * sk,struct sk_buff * skb)570*4882a593Smuzhiyun static int dccp_v6_do_rcv(struct sock *sk, struct sk_buff *skb)
571*4882a593Smuzhiyun {
572*4882a593Smuzhiyun struct ipv6_pinfo *np = inet6_sk(sk);
573*4882a593Smuzhiyun struct sk_buff *opt_skb = NULL;
574*4882a593Smuzhiyun
575*4882a593Smuzhiyun /* Imagine: socket is IPv6. IPv4 packet arrives,
576*4882a593Smuzhiyun goes to IPv4 receive handler and backlogged.
577*4882a593Smuzhiyun From backlog it always goes here. Kerboom...
578*4882a593Smuzhiyun Fortunately, dccp_rcv_established and rcv_established
579*4882a593Smuzhiyun handle them correctly, but it is not case with
580*4882a593Smuzhiyun dccp_v6_hnd_req and dccp_v6_ctl_send_reset(). --ANK
581*4882a593Smuzhiyun */
582*4882a593Smuzhiyun
583*4882a593Smuzhiyun if (skb->protocol == htons(ETH_P_IP))
584*4882a593Smuzhiyun return dccp_v4_do_rcv(sk, skb);
585*4882a593Smuzhiyun
586*4882a593Smuzhiyun if (sk_filter(sk, skb))
587*4882a593Smuzhiyun goto discard;
588*4882a593Smuzhiyun
589*4882a593Smuzhiyun /*
590*4882a593Smuzhiyun * socket locking is here for SMP purposes as backlog rcv is currently
591*4882a593Smuzhiyun * called with bh processing disabled.
592*4882a593Smuzhiyun */
593*4882a593Smuzhiyun
594*4882a593Smuzhiyun /* Do Stevens' IPV6_PKTOPTIONS.
595*4882a593Smuzhiyun
596*4882a593Smuzhiyun Yes, guys, it is the only place in our code, where we
597*4882a593Smuzhiyun may make it not affecting IPv4.
598*4882a593Smuzhiyun The rest of code is protocol independent,
599*4882a593Smuzhiyun and I do not like idea to uglify IPv4.
600*4882a593Smuzhiyun
601*4882a593Smuzhiyun Actually, all the idea behind IPV6_PKTOPTIONS
602*4882a593Smuzhiyun looks not very well thought. For now we latch
603*4882a593Smuzhiyun options, received in the last packet, enqueued
604*4882a593Smuzhiyun by tcp. Feel free to propose better solution.
605*4882a593Smuzhiyun --ANK (980728)
606*4882a593Smuzhiyun */
607*4882a593Smuzhiyun if (np->rxopt.all)
608*4882a593Smuzhiyun opt_skb = skb_clone(skb, GFP_ATOMIC);
609*4882a593Smuzhiyun
610*4882a593Smuzhiyun if (sk->sk_state == DCCP_OPEN) { /* Fast path */
611*4882a593Smuzhiyun if (dccp_rcv_established(sk, skb, dccp_hdr(skb), skb->len))
612*4882a593Smuzhiyun goto reset;
613*4882a593Smuzhiyun if (opt_skb)
614*4882a593Smuzhiyun goto ipv6_pktoptions;
615*4882a593Smuzhiyun return 0;
616*4882a593Smuzhiyun }
617*4882a593Smuzhiyun
618*4882a593Smuzhiyun /*
619*4882a593Smuzhiyun * Step 3: Process LISTEN state
620*4882a593Smuzhiyun * If S.state == LISTEN,
621*4882a593Smuzhiyun * If P.type == Request or P contains a valid Init Cookie option,
622*4882a593Smuzhiyun * (* Must scan the packet's options to check for Init
623*4882a593Smuzhiyun * Cookies. Only Init Cookies are processed here,
624*4882a593Smuzhiyun * however; other options are processed in Step 8. This
625*4882a593Smuzhiyun * scan need only be performed if the endpoint uses Init
626*4882a593Smuzhiyun * Cookies *)
627*4882a593Smuzhiyun * (* Generate a new socket and switch to that socket *)
628*4882a593Smuzhiyun * Set S := new socket for this port pair
629*4882a593Smuzhiyun * S.state = RESPOND
630*4882a593Smuzhiyun * Choose S.ISS (initial seqno) or set from Init Cookies
631*4882a593Smuzhiyun * Initialize S.GAR := S.ISS
632*4882a593Smuzhiyun * Set S.ISR, S.GSR, S.SWL, S.SWH from packet or Init Cookies
633*4882a593Smuzhiyun * Continue with S.state == RESPOND
634*4882a593Smuzhiyun * (* A Response packet will be generated in Step 11 *)
635*4882a593Smuzhiyun * Otherwise,
636*4882a593Smuzhiyun * Generate Reset(No Connection) unless P.type == Reset
637*4882a593Smuzhiyun * Drop packet and return
638*4882a593Smuzhiyun *
639*4882a593Smuzhiyun * NOTE: the check for the packet types is done in
640*4882a593Smuzhiyun * dccp_rcv_state_process
641*4882a593Smuzhiyun */
642*4882a593Smuzhiyun
643*4882a593Smuzhiyun if (dccp_rcv_state_process(sk, skb, dccp_hdr(skb), skb->len))
644*4882a593Smuzhiyun goto reset;
645*4882a593Smuzhiyun if (opt_skb)
646*4882a593Smuzhiyun goto ipv6_pktoptions;
647*4882a593Smuzhiyun return 0;
648*4882a593Smuzhiyun
649*4882a593Smuzhiyun reset:
650*4882a593Smuzhiyun dccp_v6_ctl_send_reset(sk, skb);
651*4882a593Smuzhiyun discard:
652*4882a593Smuzhiyun if (opt_skb != NULL)
653*4882a593Smuzhiyun __kfree_skb(opt_skb);
654*4882a593Smuzhiyun kfree_skb(skb);
655*4882a593Smuzhiyun return 0;
656*4882a593Smuzhiyun
657*4882a593Smuzhiyun /* Handling IPV6_PKTOPTIONS skb the similar
658*4882a593Smuzhiyun * way it's done for net/ipv6/tcp_ipv6.c
659*4882a593Smuzhiyun */
660*4882a593Smuzhiyun ipv6_pktoptions:
661*4882a593Smuzhiyun if (!((1 << sk->sk_state) & (DCCPF_CLOSED | DCCPF_LISTEN))) {
662*4882a593Smuzhiyun if (np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo)
663*4882a593Smuzhiyun np->mcast_oif = inet6_iif(opt_skb);
664*4882a593Smuzhiyun if (np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim)
665*4882a593Smuzhiyun np->mcast_hops = ipv6_hdr(opt_skb)->hop_limit;
666*4882a593Smuzhiyun if (np->rxopt.bits.rxflow || np->rxopt.bits.rxtclass)
667*4882a593Smuzhiyun np->rcv_flowinfo = ip6_flowinfo(ipv6_hdr(opt_skb));
668*4882a593Smuzhiyun if (np->repflow)
669*4882a593Smuzhiyun np->flow_label = ip6_flowlabel(ipv6_hdr(opt_skb));
670*4882a593Smuzhiyun if (ipv6_opt_accepted(sk, opt_skb,
671*4882a593Smuzhiyun &DCCP_SKB_CB(opt_skb)->header.h6)) {
672*4882a593Smuzhiyun skb_set_owner_r(opt_skb, sk);
673*4882a593Smuzhiyun memmove(IP6CB(opt_skb),
674*4882a593Smuzhiyun &DCCP_SKB_CB(opt_skb)->header.h6,
675*4882a593Smuzhiyun sizeof(struct inet6_skb_parm));
676*4882a593Smuzhiyun opt_skb = xchg(&np->pktoptions, opt_skb);
677*4882a593Smuzhiyun } else {
678*4882a593Smuzhiyun __kfree_skb(opt_skb);
679*4882a593Smuzhiyun opt_skb = xchg(&np->pktoptions, NULL);
680*4882a593Smuzhiyun }
681*4882a593Smuzhiyun }
682*4882a593Smuzhiyun
683*4882a593Smuzhiyun kfree_skb(opt_skb);
684*4882a593Smuzhiyun return 0;
685*4882a593Smuzhiyun }
686*4882a593Smuzhiyun
dccp_v6_rcv(struct sk_buff * skb)687*4882a593Smuzhiyun static int dccp_v6_rcv(struct sk_buff *skb)
688*4882a593Smuzhiyun {
689*4882a593Smuzhiyun const struct dccp_hdr *dh;
690*4882a593Smuzhiyun bool refcounted;
691*4882a593Smuzhiyun struct sock *sk;
692*4882a593Smuzhiyun int min_cov;
693*4882a593Smuzhiyun
694*4882a593Smuzhiyun /* Step 1: Check header basics */
695*4882a593Smuzhiyun
696*4882a593Smuzhiyun if (dccp_invalid_packet(skb))
697*4882a593Smuzhiyun goto discard_it;
698*4882a593Smuzhiyun
699*4882a593Smuzhiyun /* Step 1: If header checksum is incorrect, drop packet and return. */
700*4882a593Smuzhiyun if (dccp_v6_csum_finish(skb, &ipv6_hdr(skb)->saddr,
701*4882a593Smuzhiyun &ipv6_hdr(skb)->daddr)) {
702*4882a593Smuzhiyun DCCP_WARN("dropped packet with invalid checksum\n");
703*4882a593Smuzhiyun goto discard_it;
704*4882a593Smuzhiyun }
705*4882a593Smuzhiyun
706*4882a593Smuzhiyun dh = dccp_hdr(skb);
707*4882a593Smuzhiyun
708*4882a593Smuzhiyun DCCP_SKB_CB(skb)->dccpd_seq = dccp_hdr_seq(dh);
709*4882a593Smuzhiyun DCCP_SKB_CB(skb)->dccpd_type = dh->dccph_type;
710*4882a593Smuzhiyun
711*4882a593Smuzhiyun if (dccp_packet_without_ack(skb))
712*4882a593Smuzhiyun DCCP_SKB_CB(skb)->dccpd_ack_seq = DCCP_PKT_WITHOUT_ACK_SEQ;
713*4882a593Smuzhiyun else
714*4882a593Smuzhiyun DCCP_SKB_CB(skb)->dccpd_ack_seq = dccp_hdr_ack_seq(skb);
715*4882a593Smuzhiyun
716*4882a593Smuzhiyun lookup:
717*4882a593Smuzhiyun sk = __inet6_lookup_skb(&dccp_hashinfo, skb, __dccp_hdr_len(dh),
718*4882a593Smuzhiyun dh->dccph_sport, dh->dccph_dport,
719*4882a593Smuzhiyun inet6_iif(skb), 0, &refcounted);
720*4882a593Smuzhiyun if (!sk) {
721*4882a593Smuzhiyun dccp_pr_debug("failed to look up flow ID in table and "
722*4882a593Smuzhiyun "get corresponding socket\n");
723*4882a593Smuzhiyun goto no_dccp_socket;
724*4882a593Smuzhiyun }
725*4882a593Smuzhiyun
726*4882a593Smuzhiyun /*
727*4882a593Smuzhiyun * Step 2:
728*4882a593Smuzhiyun * ... or S.state == TIMEWAIT,
729*4882a593Smuzhiyun * Generate Reset(No Connection) unless P.type == Reset
730*4882a593Smuzhiyun * Drop packet and return
731*4882a593Smuzhiyun */
732*4882a593Smuzhiyun if (sk->sk_state == DCCP_TIME_WAIT) {
733*4882a593Smuzhiyun dccp_pr_debug("sk->sk_state == DCCP_TIME_WAIT: do_time_wait\n");
734*4882a593Smuzhiyun inet_twsk_put(inet_twsk(sk));
735*4882a593Smuzhiyun goto no_dccp_socket;
736*4882a593Smuzhiyun }
737*4882a593Smuzhiyun
738*4882a593Smuzhiyun if (sk->sk_state == DCCP_NEW_SYN_RECV) {
739*4882a593Smuzhiyun struct request_sock *req = inet_reqsk(sk);
740*4882a593Smuzhiyun struct sock *nsk;
741*4882a593Smuzhiyun
742*4882a593Smuzhiyun sk = req->rsk_listener;
743*4882a593Smuzhiyun if (unlikely(sk->sk_state != DCCP_LISTEN)) {
744*4882a593Smuzhiyun inet_csk_reqsk_queue_drop_and_put(sk, req);
745*4882a593Smuzhiyun goto lookup;
746*4882a593Smuzhiyun }
747*4882a593Smuzhiyun sock_hold(sk);
748*4882a593Smuzhiyun refcounted = true;
749*4882a593Smuzhiyun nsk = dccp_check_req(sk, skb, req);
750*4882a593Smuzhiyun if (!nsk) {
751*4882a593Smuzhiyun reqsk_put(req);
752*4882a593Smuzhiyun goto discard_and_relse;
753*4882a593Smuzhiyun }
754*4882a593Smuzhiyun if (nsk == sk) {
755*4882a593Smuzhiyun reqsk_put(req);
756*4882a593Smuzhiyun } else if (dccp_child_process(sk, nsk, skb)) {
757*4882a593Smuzhiyun dccp_v6_ctl_send_reset(sk, skb);
758*4882a593Smuzhiyun goto discard_and_relse;
759*4882a593Smuzhiyun } else {
760*4882a593Smuzhiyun sock_put(sk);
761*4882a593Smuzhiyun return 0;
762*4882a593Smuzhiyun }
763*4882a593Smuzhiyun }
764*4882a593Smuzhiyun /*
765*4882a593Smuzhiyun * RFC 4340, sec. 9.2.1: Minimum Checksum Coverage
766*4882a593Smuzhiyun * o if MinCsCov = 0, only packets with CsCov = 0 are accepted
767*4882a593Smuzhiyun * o if MinCsCov > 0, also accept packets with CsCov >= MinCsCov
768*4882a593Smuzhiyun */
769*4882a593Smuzhiyun min_cov = dccp_sk(sk)->dccps_pcrlen;
770*4882a593Smuzhiyun if (dh->dccph_cscov && (min_cov == 0 || dh->dccph_cscov < min_cov)) {
771*4882a593Smuzhiyun dccp_pr_debug("Packet CsCov %d does not satisfy MinCsCov %d\n",
772*4882a593Smuzhiyun dh->dccph_cscov, min_cov);
773*4882a593Smuzhiyun /* FIXME: send Data Dropped option (see also dccp_v4_rcv) */
774*4882a593Smuzhiyun goto discard_and_relse;
775*4882a593Smuzhiyun }
776*4882a593Smuzhiyun
777*4882a593Smuzhiyun if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb))
778*4882a593Smuzhiyun goto discard_and_relse;
779*4882a593Smuzhiyun
780*4882a593Smuzhiyun return __sk_receive_skb(sk, skb, 1, dh->dccph_doff * 4,
781*4882a593Smuzhiyun refcounted) ? -1 : 0;
782*4882a593Smuzhiyun
783*4882a593Smuzhiyun no_dccp_socket:
784*4882a593Smuzhiyun if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb))
785*4882a593Smuzhiyun goto discard_it;
786*4882a593Smuzhiyun /*
787*4882a593Smuzhiyun * Step 2:
788*4882a593Smuzhiyun * If no socket ...
789*4882a593Smuzhiyun * Generate Reset(No Connection) unless P.type == Reset
790*4882a593Smuzhiyun * Drop packet and return
791*4882a593Smuzhiyun */
792*4882a593Smuzhiyun if (dh->dccph_type != DCCP_PKT_RESET) {
793*4882a593Smuzhiyun DCCP_SKB_CB(skb)->dccpd_reset_code =
794*4882a593Smuzhiyun DCCP_RESET_CODE_NO_CONNECTION;
795*4882a593Smuzhiyun dccp_v6_ctl_send_reset(sk, skb);
796*4882a593Smuzhiyun }
797*4882a593Smuzhiyun
798*4882a593Smuzhiyun discard_it:
799*4882a593Smuzhiyun kfree_skb(skb);
800*4882a593Smuzhiyun return 0;
801*4882a593Smuzhiyun
802*4882a593Smuzhiyun discard_and_relse:
803*4882a593Smuzhiyun if (refcounted)
804*4882a593Smuzhiyun sock_put(sk);
805*4882a593Smuzhiyun goto discard_it;
806*4882a593Smuzhiyun }
807*4882a593Smuzhiyun
dccp_v6_connect(struct sock * sk,struct sockaddr * uaddr,int addr_len)808*4882a593Smuzhiyun static int dccp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
809*4882a593Smuzhiyun int addr_len)
810*4882a593Smuzhiyun {
811*4882a593Smuzhiyun struct sockaddr_in6 *usin = (struct sockaddr_in6 *)uaddr;
812*4882a593Smuzhiyun struct inet_connection_sock *icsk = inet_csk(sk);
813*4882a593Smuzhiyun struct inet_sock *inet = inet_sk(sk);
814*4882a593Smuzhiyun struct ipv6_pinfo *np = inet6_sk(sk);
815*4882a593Smuzhiyun struct dccp_sock *dp = dccp_sk(sk);
816*4882a593Smuzhiyun struct in6_addr *saddr = NULL, *final_p, final;
817*4882a593Smuzhiyun struct ipv6_txoptions *opt;
818*4882a593Smuzhiyun struct flowi6 fl6;
819*4882a593Smuzhiyun struct dst_entry *dst;
820*4882a593Smuzhiyun int addr_type;
821*4882a593Smuzhiyun int err;
822*4882a593Smuzhiyun
823*4882a593Smuzhiyun dp->dccps_role = DCCP_ROLE_CLIENT;
824*4882a593Smuzhiyun
825*4882a593Smuzhiyun if (addr_len < SIN6_LEN_RFC2133)
826*4882a593Smuzhiyun return -EINVAL;
827*4882a593Smuzhiyun
828*4882a593Smuzhiyun if (usin->sin6_family != AF_INET6)
829*4882a593Smuzhiyun return -EAFNOSUPPORT;
830*4882a593Smuzhiyun
831*4882a593Smuzhiyun memset(&fl6, 0, sizeof(fl6));
832*4882a593Smuzhiyun
833*4882a593Smuzhiyun if (np->sndflow) {
834*4882a593Smuzhiyun fl6.flowlabel = usin->sin6_flowinfo & IPV6_FLOWINFO_MASK;
835*4882a593Smuzhiyun IP6_ECN_flow_init(fl6.flowlabel);
836*4882a593Smuzhiyun if (fl6.flowlabel & IPV6_FLOWLABEL_MASK) {
837*4882a593Smuzhiyun struct ip6_flowlabel *flowlabel;
838*4882a593Smuzhiyun flowlabel = fl6_sock_lookup(sk, fl6.flowlabel);
839*4882a593Smuzhiyun if (IS_ERR(flowlabel))
840*4882a593Smuzhiyun return -EINVAL;
841*4882a593Smuzhiyun fl6_sock_release(flowlabel);
842*4882a593Smuzhiyun }
843*4882a593Smuzhiyun }
844*4882a593Smuzhiyun /*
845*4882a593Smuzhiyun * connect() to INADDR_ANY means loopback (BSD'ism).
846*4882a593Smuzhiyun */
847*4882a593Smuzhiyun if (ipv6_addr_any(&usin->sin6_addr))
848*4882a593Smuzhiyun usin->sin6_addr.s6_addr[15] = 1;
849*4882a593Smuzhiyun
850*4882a593Smuzhiyun addr_type = ipv6_addr_type(&usin->sin6_addr);
851*4882a593Smuzhiyun
852*4882a593Smuzhiyun if (addr_type & IPV6_ADDR_MULTICAST)
853*4882a593Smuzhiyun return -ENETUNREACH;
854*4882a593Smuzhiyun
855*4882a593Smuzhiyun if (addr_type & IPV6_ADDR_LINKLOCAL) {
856*4882a593Smuzhiyun if (addr_len >= sizeof(struct sockaddr_in6) &&
857*4882a593Smuzhiyun usin->sin6_scope_id) {
858*4882a593Smuzhiyun /* If interface is set while binding, indices
859*4882a593Smuzhiyun * must coincide.
860*4882a593Smuzhiyun */
861*4882a593Smuzhiyun if (sk->sk_bound_dev_if &&
862*4882a593Smuzhiyun sk->sk_bound_dev_if != usin->sin6_scope_id)
863*4882a593Smuzhiyun return -EINVAL;
864*4882a593Smuzhiyun
865*4882a593Smuzhiyun sk->sk_bound_dev_if = usin->sin6_scope_id;
866*4882a593Smuzhiyun }
867*4882a593Smuzhiyun
868*4882a593Smuzhiyun /* Connect to link-local address requires an interface */
869*4882a593Smuzhiyun if (!sk->sk_bound_dev_if)
870*4882a593Smuzhiyun return -EINVAL;
871*4882a593Smuzhiyun }
872*4882a593Smuzhiyun
873*4882a593Smuzhiyun sk->sk_v6_daddr = usin->sin6_addr;
874*4882a593Smuzhiyun np->flow_label = fl6.flowlabel;
875*4882a593Smuzhiyun
876*4882a593Smuzhiyun /*
877*4882a593Smuzhiyun * DCCP over IPv4
878*4882a593Smuzhiyun */
879*4882a593Smuzhiyun if (addr_type == IPV6_ADDR_MAPPED) {
880*4882a593Smuzhiyun u32 exthdrlen = icsk->icsk_ext_hdr_len;
881*4882a593Smuzhiyun struct sockaddr_in sin;
882*4882a593Smuzhiyun
883*4882a593Smuzhiyun SOCK_DEBUG(sk, "connect: ipv4 mapped\n");
884*4882a593Smuzhiyun
885*4882a593Smuzhiyun if (__ipv6_only_sock(sk))
886*4882a593Smuzhiyun return -ENETUNREACH;
887*4882a593Smuzhiyun
888*4882a593Smuzhiyun sin.sin_family = AF_INET;
889*4882a593Smuzhiyun sin.sin_port = usin->sin6_port;
890*4882a593Smuzhiyun sin.sin_addr.s_addr = usin->sin6_addr.s6_addr32[3];
891*4882a593Smuzhiyun
892*4882a593Smuzhiyun icsk->icsk_af_ops = &dccp_ipv6_mapped;
893*4882a593Smuzhiyun sk->sk_backlog_rcv = dccp_v4_do_rcv;
894*4882a593Smuzhiyun
895*4882a593Smuzhiyun err = dccp_v4_connect(sk, (struct sockaddr *)&sin, sizeof(sin));
896*4882a593Smuzhiyun if (err) {
897*4882a593Smuzhiyun icsk->icsk_ext_hdr_len = exthdrlen;
898*4882a593Smuzhiyun icsk->icsk_af_ops = &dccp_ipv6_af_ops;
899*4882a593Smuzhiyun sk->sk_backlog_rcv = dccp_v6_do_rcv;
900*4882a593Smuzhiyun goto failure;
901*4882a593Smuzhiyun }
902*4882a593Smuzhiyun np->saddr = sk->sk_v6_rcv_saddr;
903*4882a593Smuzhiyun return err;
904*4882a593Smuzhiyun }
905*4882a593Smuzhiyun
906*4882a593Smuzhiyun if (!ipv6_addr_any(&sk->sk_v6_rcv_saddr))
907*4882a593Smuzhiyun saddr = &sk->sk_v6_rcv_saddr;
908*4882a593Smuzhiyun
909*4882a593Smuzhiyun fl6.flowi6_proto = IPPROTO_DCCP;
910*4882a593Smuzhiyun fl6.daddr = sk->sk_v6_daddr;
911*4882a593Smuzhiyun fl6.saddr = saddr ? *saddr : np->saddr;
912*4882a593Smuzhiyun fl6.flowi6_oif = sk->sk_bound_dev_if;
913*4882a593Smuzhiyun fl6.fl6_dport = usin->sin6_port;
914*4882a593Smuzhiyun fl6.fl6_sport = inet->inet_sport;
915*4882a593Smuzhiyun security_sk_classify_flow(sk, flowi6_to_flowi_common(&fl6));
916*4882a593Smuzhiyun
917*4882a593Smuzhiyun opt = rcu_dereference_protected(np->opt, lockdep_sock_is_held(sk));
918*4882a593Smuzhiyun final_p = fl6_update_dst(&fl6, opt, &final);
919*4882a593Smuzhiyun
920*4882a593Smuzhiyun dst = ip6_dst_lookup_flow(sock_net(sk), sk, &fl6, final_p);
921*4882a593Smuzhiyun if (IS_ERR(dst)) {
922*4882a593Smuzhiyun err = PTR_ERR(dst);
923*4882a593Smuzhiyun goto failure;
924*4882a593Smuzhiyun }
925*4882a593Smuzhiyun
926*4882a593Smuzhiyun if (saddr == NULL) {
927*4882a593Smuzhiyun saddr = &fl6.saddr;
928*4882a593Smuzhiyun sk->sk_v6_rcv_saddr = *saddr;
929*4882a593Smuzhiyun }
930*4882a593Smuzhiyun
931*4882a593Smuzhiyun /* set the source address */
932*4882a593Smuzhiyun np->saddr = *saddr;
933*4882a593Smuzhiyun inet->inet_rcv_saddr = LOOPBACK4_IPV6;
934*4882a593Smuzhiyun
935*4882a593Smuzhiyun ip6_dst_store(sk, dst, NULL, NULL);
936*4882a593Smuzhiyun
937*4882a593Smuzhiyun icsk->icsk_ext_hdr_len = 0;
938*4882a593Smuzhiyun if (opt)
939*4882a593Smuzhiyun icsk->icsk_ext_hdr_len = opt->opt_flen + opt->opt_nflen;
940*4882a593Smuzhiyun
941*4882a593Smuzhiyun inet->inet_dport = usin->sin6_port;
942*4882a593Smuzhiyun
943*4882a593Smuzhiyun dccp_set_state(sk, DCCP_REQUESTING);
944*4882a593Smuzhiyun err = inet6_hash_connect(&dccp_death_row, sk);
945*4882a593Smuzhiyun if (err)
946*4882a593Smuzhiyun goto late_failure;
947*4882a593Smuzhiyun
948*4882a593Smuzhiyun dp->dccps_iss = secure_dccpv6_sequence_number(np->saddr.s6_addr32,
949*4882a593Smuzhiyun sk->sk_v6_daddr.s6_addr32,
950*4882a593Smuzhiyun inet->inet_sport,
951*4882a593Smuzhiyun inet->inet_dport);
952*4882a593Smuzhiyun err = dccp_connect(sk);
953*4882a593Smuzhiyun if (err)
954*4882a593Smuzhiyun goto late_failure;
955*4882a593Smuzhiyun
956*4882a593Smuzhiyun return 0;
957*4882a593Smuzhiyun
958*4882a593Smuzhiyun late_failure:
959*4882a593Smuzhiyun dccp_set_state(sk, DCCP_CLOSED);
960*4882a593Smuzhiyun if (!(sk->sk_userlocks & SOCK_BINDADDR_LOCK))
961*4882a593Smuzhiyun inet_reset_saddr(sk);
962*4882a593Smuzhiyun __sk_dst_reset(sk);
963*4882a593Smuzhiyun failure:
964*4882a593Smuzhiyun inet->inet_dport = 0;
965*4882a593Smuzhiyun sk->sk_route_caps = 0;
966*4882a593Smuzhiyun return err;
967*4882a593Smuzhiyun }
968*4882a593Smuzhiyun
969*4882a593Smuzhiyun static const struct inet_connection_sock_af_ops dccp_ipv6_af_ops = {
970*4882a593Smuzhiyun .queue_xmit = inet6_csk_xmit,
971*4882a593Smuzhiyun .send_check = dccp_v6_send_check,
972*4882a593Smuzhiyun .rebuild_header = inet6_sk_rebuild_header,
973*4882a593Smuzhiyun .conn_request = dccp_v6_conn_request,
974*4882a593Smuzhiyun .syn_recv_sock = dccp_v6_request_recv_sock,
975*4882a593Smuzhiyun .net_header_len = sizeof(struct ipv6hdr),
976*4882a593Smuzhiyun .setsockopt = ipv6_setsockopt,
977*4882a593Smuzhiyun .getsockopt = ipv6_getsockopt,
978*4882a593Smuzhiyun .addr2sockaddr = inet6_csk_addr2sockaddr,
979*4882a593Smuzhiyun .sockaddr_len = sizeof(struct sockaddr_in6),
980*4882a593Smuzhiyun };
981*4882a593Smuzhiyun
982*4882a593Smuzhiyun /*
983*4882a593Smuzhiyun * DCCP over IPv4 via INET6 API
984*4882a593Smuzhiyun */
985*4882a593Smuzhiyun static const struct inet_connection_sock_af_ops dccp_ipv6_mapped = {
986*4882a593Smuzhiyun .queue_xmit = ip_queue_xmit,
987*4882a593Smuzhiyun .send_check = dccp_v4_send_check,
988*4882a593Smuzhiyun .rebuild_header = inet_sk_rebuild_header,
989*4882a593Smuzhiyun .conn_request = dccp_v6_conn_request,
990*4882a593Smuzhiyun .syn_recv_sock = dccp_v6_request_recv_sock,
991*4882a593Smuzhiyun .net_header_len = sizeof(struct iphdr),
992*4882a593Smuzhiyun .setsockopt = ipv6_setsockopt,
993*4882a593Smuzhiyun .getsockopt = ipv6_getsockopt,
994*4882a593Smuzhiyun .addr2sockaddr = inet6_csk_addr2sockaddr,
995*4882a593Smuzhiyun .sockaddr_len = sizeof(struct sockaddr_in6),
996*4882a593Smuzhiyun };
997*4882a593Smuzhiyun
998*4882a593Smuzhiyun /* NOTE: A lot of things set to zero explicitly by call to
999*4882a593Smuzhiyun * sk_alloc() so need not be done here.
1000*4882a593Smuzhiyun */
dccp_v6_init_sock(struct sock * sk)1001*4882a593Smuzhiyun static int dccp_v6_init_sock(struct sock *sk)
1002*4882a593Smuzhiyun {
1003*4882a593Smuzhiyun static __u8 dccp_v6_ctl_sock_initialized;
1004*4882a593Smuzhiyun int err = dccp_init_sock(sk, dccp_v6_ctl_sock_initialized);
1005*4882a593Smuzhiyun
1006*4882a593Smuzhiyun if (err == 0) {
1007*4882a593Smuzhiyun if (unlikely(!dccp_v6_ctl_sock_initialized))
1008*4882a593Smuzhiyun dccp_v6_ctl_sock_initialized = 1;
1009*4882a593Smuzhiyun inet_csk(sk)->icsk_af_ops = &dccp_ipv6_af_ops;
1010*4882a593Smuzhiyun }
1011*4882a593Smuzhiyun
1012*4882a593Smuzhiyun return err;
1013*4882a593Smuzhiyun }
1014*4882a593Smuzhiyun
dccp_v6_destroy_sock(struct sock * sk)1015*4882a593Smuzhiyun static void dccp_v6_destroy_sock(struct sock *sk)
1016*4882a593Smuzhiyun {
1017*4882a593Smuzhiyun dccp_destroy_sock(sk);
1018*4882a593Smuzhiyun inet6_destroy_sock(sk);
1019*4882a593Smuzhiyun }
1020*4882a593Smuzhiyun
1021*4882a593Smuzhiyun static struct timewait_sock_ops dccp6_timewait_sock_ops = {
1022*4882a593Smuzhiyun .twsk_obj_size = sizeof(struct dccp6_timewait_sock),
1023*4882a593Smuzhiyun };
1024*4882a593Smuzhiyun
1025*4882a593Smuzhiyun static struct proto dccp_v6_prot = {
1026*4882a593Smuzhiyun .name = "DCCPv6",
1027*4882a593Smuzhiyun .owner = THIS_MODULE,
1028*4882a593Smuzhiyun .close = dccp_close,
1029*4882a593Smuzhiyun .connect = dccp_v6_connect,
1030*4882a593Smuzhiyun .disconnect = dccp_disconnect,
1031*4882a593Smuzhiyun .ioctl = dccp_ioctl,
1032*4882a593Smuzhiyun .init = dccp_v6_init_sock,
1033*4882a593Smuzhiyun .setsockopt = dccp_setsockopt,
1034*4882a593Smuzhiyun .getsockopt = dccp_getsockopt,
1035*4882a593Smuzhiyun .sendmsg = dccp_sendmsg,
1036*4882a593Smuzhiyun .recvmsg = dccp_recvmsg,
1037*4882a593Smuzhiyun .backlog_rcv = dccp_v6_do_rcv,
1038*4882a593Smuzhiyun .hash = inet6_hash,
1039*4882a593Smuzhiyun .unhash = inet_unhash,
1040*4882a593Smuzhiyun .accept = inet_csk_accept,
1041*4882a593Smuzhiyun .get_port = inet_csk_get_port,
1042*4882a593Smuzhiyun .shutdown = dccp_shutdown,
1043*4882a593Smuzhiyun .destroy = dccp_v6_destroy_sock,
1044*4882a593Smuzhiyun .orphan_count = &dccp_orphan_count,
1045*4882a593Smuzhiyun .max_header = MAX_DCCP_HEADER,
1046*4882a593Smuzhiyun .obj_size = sizeof(struct dccp6_sock),
1047*4882a593Smuzhiyun .slab_flags = SLAB_TYPESAFE_BY_RCU,
1048*4882a593Smuzhiyun .rsk_prot = &dccp6_request_sock_ops,
1049*4882a593Smuzhiyun .twsk_prot = &dccp6_timewait_sock_ops,
1050*4882a593Smuzhiyun .h.hashinfo = &dccp_hashinfo,
1051*4882a593Smuzhiyun };
1052*4882a593Smuzhiyun
1053*4882a593Smuzhiyun static const struct inet6_protocol dccp_v6_protocol = {
1054*4882a593Smuzhiyun .handler = dccp_v6_rcv,
1055*4882a593Smuzhiyun .err_handler = dccp_v6_err,
1056*4882a593Smuzhiyun .flags = INET6_PROTO_NOPOLICY | INET6_PROTO_FINAL,
1057*4882a593Smuzhiyun };
1058*4882a593Smuzhiyun
1059*4882a593Smuzhiyun static const struct proto_ops inet6_dccp_ops = {
1060*4882a593Smuzhiyun .family = PF_INET6,
1061*4882a593Smuzhiyun .owner = THIS_MODULE,
1062*4882a593Smuzhiyun .release = inet6_release,
1063*4882a593Smuzhiyun .bind = inet6_bind,
1064*4882a593Smuzhiyun .connect = inet_stream_connect,
1065*4882a593Smuzhiyun .socketpair = sock_no_socketpair,
1066*4882a593Smuzhiyun .accept = inet_accept,
1067*4882a593Smuzhiyun .getname = inet6_getname,
1068*4882a593Smuzhiyun .poll = dccp_poll,
1069*4882a593Smuzhiyun .ioctl = inet6_ioctl,
1070*4882a593Smuzhiyun .gettstamp = sock_gettstamp,
1071*4882a593Smuzhiyun .listen = inet_dccp_listen,
1072*4882a593Smuzhiyun .shutdown = inet_shutdown,
1073*4882a593Smuzhiyun .setsockopt = sock_common_setsockopt,
1074*4882a593Smuzhiyun .getsockopt = sock_common_getsockopt,
1075*4882a593Smuzhiyun .sendmsg = inet_sendmsg,
1076*4882a593Smuzhiyun .recvmsg = sock_common_recvmsg,
1077*4882a593Smuzhiyun .mmap = sock_no_mmap,
1078*4882a593Smuzhiyun .sendpage = sock_no_sendpage,
1079*4882a593Smuzhiyun #ifdef CONFIG_COMPAT
1080*4882a593Smuzhiyun .compat_ioctl = inet6_compat_ioctl,
1081*4882a593Smuzhiyun #endif
1082*4882a593Smuzhiyun };
1083*4882a593Smuzhiyun
1084*4882a593Smuzhiyun static struct inet_protosw dccp_v6_protosw = {
1085*4882a593Smuzhiyun .type = SOCK_DCCP,
1086*4882a593Smuzhiyun .protocol = IPPROTO_DCCP,
1087*4882a593Smuzhiyun .prot = &dccp_v6_prot,
1088*4882a593Smuzhiyun .ops = &inet6_dccp_ops,
1089*4882a593Smuzhiyun .flags = INET_PROTOSW_ICSK,
1090*4882a593Smuzhiyun };
1091*4882a593Smuzhiyun
dccp_v6_init_net(struct net * net)1092*4882a593Smuzhiyun static int __net_init dccp_v6_init_net(struct net *net)
1093*4882a593Smuzhiyun {
1094*4882a593Smuzhiyun if (dccp_hashinfo.bhash == NULL)
1095*4882a593Smuzhiyun return -ESOCKTNOSUPPORT;
1096*4882a593Smuzhiyun
1097*4882a593Smuzhiyun return inet_ctl_sock_create(&net->dccp.v6_ctl_sk, PF_INET6,
1098*4882a593Smuzhiyun SOCK_DCCP, IPPROTO_DCCP, net);
1099*4882a593Smuzhiyun }
1100*4882a593Smuzhiyun
dccp_v6_exit_net(struct net * net)1101*4882a593Smuzhiyun static void __net_exit dccp_v6_exit_net(struct net *net)
1102*4882a593Smuzhiyun {
1103*4882a593Smuzhiyun inet_ctl_sock_destroy(net->dccp.v6_ctl_sk);
1104*4882a593Smuzhiyun }
1105*4882a593Smuzhiyun
dccp_v6_exit_batch(struct list_head * net_exit_list)1106*4882a593Smuzhiyun static void __net_exit dccp_v6_exit_batch(struct list_head *net_exit_list)
1107*4882a593Smuzhiyun {
1108*4882a593Smuzhiyun inet_twsk_purge(&dccp_hashinfo, AF_INET6);
1109*4882a593Smuzhiyun }
1110*4882a593Smuzhiyun
1111*4882a593Smuzhiyun static struct pernet_operations dccp_v6_ops = {
1112*4882a593Smuzhiyun .init = dccp_v6_init_net,
1113*4882a593Smuzhiyun .exit = dccp_v6_exit_net,
1114*4882a593Smuzhiyun .exit_batch = dccp_v6_exit_batch,
1115*4882a593Smuzhiyun };
1116*4882a593Smuzhiyun
dccp_v6_init(void)1117*4882a593Smuzhiyun static int __init dccp_v6_init(void)
1118*4882a593Smuzhiyun {
1119*4882a593Smuzhiyun int err = proto_register(&dccp_v6_prot, 1);
1120*4882a593Smuzhiyun
1121*4882a593Smuzhiyun if (err)
1122*4882a593Smuzhiyun goto out;
1123*4882a593Smuzhiyun
1124*4882a593Smuzhiyun inet6_register_protosw(&dccp_v6_protosw);
1125*4882a593Smuzhiyun
1126*4882a593Smuzhiyun err = register_pernet_subsys(&dccp_v6_ops);
1127*4882a593Smuzhiyun if (err)
1128*4882a593Smuzhiyun goto out_destroy_ctl_sock;
1129*4882a593Smuzhiyun
1130*4882a593Smuzhiyun err = inet6_add_protocol(&dccp_v6_protocol, IPPROTO_DCCP);
1131*4882a593Smuzhiyun if (err)
1132*4882a593Smuzhiyun goto out_unregister_proto;
1133*4882a593Smuzhiyun
1134*4882a593Smuzhiyun out:
1135*4882a593Smuzhiyun return err;
1136*4882a593Smuzhiyun out_unregister_proto:
1137*4882a593Smuzhiyun unregister_pernet_subsys(&dccp_v6_ops);
1138*4882a593Smuzhiyun out_destroy_ctl_sock:
1139*4882a593Smuzhiyun inet6_unregister_protosw(&dccp_v6_protosw);
1140*4882a593Smuzhiyun proto_unregister(&dccp_v6_prot);
1141*4882a593Smuzhiyun goto out;
1142*4882a593Smuzhiyun }
1143*4882a593Smuzhiyun
dccp_v6_exit(void)1144*4882a593Smuzhiyun static void __exit dccp_v6_exit(void)
1145*4882a593Smuzhiyun {
1146*4882a593Smuzhiyun inet6_del_protocol(&dccp_v6_protocol, IPPROTO_DCCP);
1147*4882a593Smuzhiyun unregister_pernet_subsys(&dccp_v6_ops);
1148*4882a593Smuzhiyun inet6_unregister_protosw(&dccp_v6_protosw);
1149*4882a593Smuzhiyun proto_unregister(&dccp_v6_prot);
1150*4882a593Smuzhiyun }
1151*4882a593Smuzhiyun
1152*4882a593Smuzhiyun module_init(dccp_v6_init);
1153*4882a593Smuzhiyun module_exit(dccp_v6_exit);
1154*4882a593Smuzhiyun
1155*4882a593Smuzhiyun /*
1156*4882a593Smuzhiyun * __stringify doesn't likes enums, so use SOCK_DCCP (6) and IPPROTO_DCCP (33)
1157*4882a593Smuzhiyun * values directly, Also cover the case where the protocol is not specified,
1158*4882a593Smuzhiyun * i.e. net-pf-PF_INET6-proto-0-type-SOCK_DCCP
1159*4882a593Smuzhiyun */
1160*4882a593Smuzhiyun MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_INET6, 33, 6);
1161*4882a593Smuzhiyun MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_INET6, 0, 6);
1162*4882a593Smuzhiyun MODULE_LICENSE("GPL");
1163*4882a593Smuzhiyun MODULE_AUTHOR("Arnaldo Carvalho de Melo <acme@mandriva.com>");
1164*4882a593Smuzhiyun MODULE_DESCRIPTION("DCCPv6 - Datagram Congestion Controlled Protocol");
1165