12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
23df80d93SArnaldo Carvalho de Melo /*
33df80d93SArnaldo Carvalho de Melo * DCCP over IPv6
43df80d93SArnaldo Carvalho de Melo * Linux INET6 implementation
53df80d93SArnaldo Carvalho de Melo *
63df80d93SArnaldo Carvalho de Melo * Based on net/dccp6/ipv6.c
73df80d93SArnaldo Carvalho de Melo *
83df80d93SArnaldo Carvalho de Melo * Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
93df80d93SArnaldo Carvalho de Melo */
103df80d93SArnaldo Carvalho de Melo
113df80d93SArnaldo Carvalho de Melo #include <linux/module.h>
123df80d93SArnaldo Carvalho de Melo #include <linux/random.h>
135a0e3ad6STejun Heo #include <linux/slab.h>
143df80d93SArnaldo Carvalho de Melo #include <linux/xfrm.h>
15323fbd0eSAndrii #include <linux/string.h>
163df80d93SArnaldo Carvalho de Melo
173df80d93SArnaldo Carvalho de Melo #include <net/addrconf.h>
183df80d93SArnaldo Carvalho de Melo #include <net/inet_common.h>
193df80d93SArnaldo Carvalho de Melo #include <net/inet_hashtables.h>
2014c85021SArnaldo Carvalho de Melo #include <net/inet_sock.h>
213df80d93SArnaldo Carvalho de Melo #include <net/inet6_connection_sock.h>
223df80d93SArnaldo Carvalho de Melo #include <net/inet6_hashtables.h>
233df80d93SArnaldo Carvalho de Melo #include <net/ip6_route.h>
243df80d93SArnaldo Carvalho de Melo #include <net/ipv6.h>
253df80d93SArnaldo Carvalho de Melo #include <net/protocol.h>
263df80d93SArnaldo Carvalho de Melo #include <net/transp_v6.h>
27aa0e4e4aSDavid S. Miller #include <net/ip6_checksum.h>
283df80d93SArnaldo Carvalho de Melo #include <net/xfrm.h>
296e5714eaSDavid S. Miller #include <net/secure_seq.h>
30b98b3304SFlorian Westphal #include <net/netns/generic.h>
31323fbd0eSAndrii #include <net/sock.h>
323df80d93SArnaldo Carvalho de Melo
333df80d93SArnaldo Carvalho de Melo #include "dccp.h"
343df80d93SArnaldo Carvalho de Melo #include "ipv6.h"
354b79f0afSIan McDonald #include "feat.h"
363df80d93SArnaldo Carvalho de Melo
37b98b3304SFlorian Westphal struct dccp_v6_pernet {
38b98b3304SFlorian Westphal struct sock *v6_ctl_sk;
39b98b3304SFlorian Westphal };
40b98b3304SFlorian Westphal
41b98b3304SFlorian Westphal static unsigned int dccp_v6_pernet_id __read_mostly;
42b98b3304SFlorian Westphal
43b98b3304SFlorian Westphal /* The per-net v6_ctl_sk is used for sending RSTs and ACKs */
4472478873SArnaldo Carvalho de Melo
453b401a81SStephen Hemminger static const struct inet_connection_sock_af_ops dccp_ipv6_mapped;
463b401a81SStephen Hemminger static const struct inet_connection_sock_af_ops dccp_ipv6_af_ops;
473df80d93SArnaldo Carvalho de Melo
486f4e5fffSGerrit Renker /* 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)49868c86bcSAl Viro static inline __sum16 dccp_v6_csum_finish(struct sk_buff *skb,
50b71d1d42SEric Dumazet const struct in6_addr *saddr,
51b71d1d42SEric Dumazet const struct in6_addr *daddr)
523df80d93SArnaldo Carvalho de Melo {
536f4e5fffSGerrit Renker return csum_ipv6_magic(saddr, daddr, skb->len, IPPROTO_DCCP, skb->csum);
546f4e5fffSGerrit Renker }
556f4e5fffSGerrit Renker
dccp_v6_send_check(struct sock * sk,struct sk_buff * skb)56bb296246SHerbert Xu static inline void dccp_v6_send_check(struct sock *sk, struct sk_buff *skb)
576f4e5fffSGerrit Renker {
586f4e5fffSGerrit Renker struct ipv6_pinfo *np = inet6_sk(sk);
596f4e5fffSGerrit Renker struct dccp_hdr *dh = dccp_hdr(skb);
606f4e5fffSGerrit Renker
616f4e5fffSGerrit Renker dccp_csum_outgoing(skb);
62efe4208fSEric Dumazet dh->dccph_checksum = dccp_v6_csum_finish(skb, &np->saddr, &sk->sk_v6_daddr);
633df80d93SArnaldo Carvalho de Melo }
643df80d93SArnaldo Carvalho de Melo
dccp_v6_init_sequence(struct sk_buff * skb)656e5714eaSDavid S. Miller static inline __u64 dccp_v6_init_sequence(struct sk_buff *skb)
66d7f7365fSGerrit Renker {
670660e03fSArnaldo Carvalho de Melo return secure_dccpv6_sequence_number(ipv6_hdr(skb)->daddr.s6_addr32,
680660e03fSArnaldo Carvalho de Melo ipv6_hdr(skb)->saddr.s6_addr32,
69865e9022SGerrit Renker dccp_hdr(skb)->dccph_dport,
70865e9022SGerrit Renker dccp_hdr(skb)->dccph_sport );
71d7f7365fSGerrit Renker
723df80d93SArnaldo Carvalho de Melo }
733df80d93SArnaldo Carvalho de Melo
dccp_v6_err(struct sk_buff * skb,struct inet6_skb_parm * opt,u8 type,u8 code,int offset,__be32 info)7432bbd879SStefano Brivio static int dccp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
75d5fdd6baSBrian Haley u8 type, u8 code, int offset, __be32 info)
763df80d93SArnaldo Carvalho de Melo {
77977ad86cSJann Horn const struct ipv6hdr *hdr;
781aa9d1a0SEric Dumazet const struct dccp_hdr *dh;
79e0bcfb0cSWei Yongjun struct dccp_sock *dp;
803df80d93SArnaldo Carvalho de Melo struct ipv6_pinfo *np;
813df80d93SArnaldo Carvalho de Melo struct sock *sk;
823df80d93SArnaldo Carvalho de Melo int err;
833df80d93SArnaldo Carvalho de Melo __u64 seq;
84ca12a1a4SPavel Emelyanov struct net *net = dev_net(skb->dev);
853df80d93SArnaldo Carvalho de Melo
866af28974SEric Dumazet if (!pskb_may_pull(skb, offset + sizeof(*dh)))
876af28974SEric Dumazet return -EINVAL;
88977ad86cSJann Horn dh = (struct dccp_hdr *)(skb->data + offset);
89977ad86cSJann Horn if (!pskb_may_pull(skb, offset + __dccp_basic_hdr_len(dh)))
90977ad86cSJann Horn return -EINVAL;
91977ad86cSJann Horn hdr = (const struct ipv6hdr *)skb->data;
921aa9d1a0SEric Dumazet dh = (struct dccp_hdr *)(skb->data + offset);
93860239c5SWei Yongjun
9452036a43SEric Dumazet sk = __inet6_lookup_established(net, &dccp_hashinfo,
95671a1c74SPavel Emelyanov &hdr->daddr, dh->dccph_dport,
9652036a43SEric Dumazet &hdr->saddr, ntohs(dh->dccph_sport),
974297a0efSDavid Ahern inet6_iif(skb), 0);
983df80d93SArnaldo Carvalho de Melo
9952036a43SEric Dumazet if (!sk) {
100a16292a0SEric Dumazet __ICMP6_INC_STATS(net, __in6_dev_get(skb->dev),
101e41b5368SDenis V. Lunev ICMP6_MIB_INERRORS);
10232bbd879SStefano Brivio return -ENOENT;
1033df80d93SArnaldo Carvalho de Melo }
1043df80d93SArnaldo Carvalho de Melo
1053df80d93SArnaldo Carvalho de Melo if (sk->sk_state == DCCP_TIME_WAIT) {
1069469c7b4SYOSHIFUJI Hideaki inet_twsk_put(inet_twsk(sk));
10732bbd879SStefano Brivio return 0;
1083df80d93SArnaldo Carvalho de Melo }
10952036a43SEric Dumazet seq = dccp_hdr_seq(dh);
11032bbd879SStefano Brivio if (sk->sk_state == DCCP_NEW_SYN_RECV) {
11132bbd879SStefano Brivio dccp_req_err(sk, seq);
11232bbd879SStefano Brivio return 0;
11332bbd879SStefano Brivio }
1143df80d93SArnaldo Carvalho de Melo
1153df80d93SArnaldo Carvalho de Melo bh_lock_sock(sk);
1163df80d93SArnaldo Carvalho de Melo if (sock_owned_by_user(sk))
11702a1d6e7SEric Dumazet __NET_INC_STATS(net, LINUX_MIB_LOCKDROPPEDICMPS);
1183df80d93SArnaldo Carvalho de Melo
1193df80d93SArnaldo Carvalho de Melo if (sk->sk_state == DCCP_CLOSED)
1203df80d93SArnaldo Carvalho de Melo goto out;
1213df80d93SArnaldo Carvalho de Melo
122e0bcfb0cSWei Yongjun dp = dccp_sk(sk);
123e0bcfb0cSWei Yongjun if ((1 << sk->sk_state) & ~(DCCPF_REQUESTING | DCCPF_LISTEN) &&
124e0bcfb0cSWei Yongjun !between48(seq, dp->dccps_awl, dp->dccps_awh)) {
12502a1d6e7SEric Dumazet __NET_INC_STATS(net, LINUX_MIB_OUTOFWINDOWICMPS);
126e0bcfb0cSWei Yongjun goto out;
127e0bcfb0cSWei Yongjun }
128e0bcfb0cSWei Yongjun
1293df80d93SArnaldo Carvalho de Melo np = inet6_sk(sk);
1303df80d93SArnaldo Carvalho de Melo
131ec18d9a2SDavid S. Miller if (type == NDISC_REDIRECT) {
13245caeaa5SJon Maxwell if (!sock_owned_by_user(sk)) {
133ec18d9a2SDavid S. Miller struct dst_entry *dst = __sk_dst_check(sk, np->dst_cookie);
134ec18d9a2SDavid S. Miller
1351ed5c48fSDavid S. Miller if (dst)
1366700c270SDavid S. Miller dst->ops->redirect(dst, sk, skb);
13745caeaa5SJon Maxwell }
138bd784a14SDuan Jiong goto out;
139ec18d9a2SDavid S. Miller }
140ec18d9a2SDavid S. Miller
1413df80d93SArnaldo Carvalho de Melo if (type == ICMPV6_PKT_TOOBIG) {
1423df80d93SArnaldo Carvalho de Melo struct dst_entry *dst = NULL;
1433df80d93SArnaldo Carvalho de Melo
14493b36cf3SHannes Frederic Sowa if (!ip6_sk_accept_pmtu(sk))
14593b36cf3SHannes Frederic Sowa goto out;
14693b36cf3SHannes Frederic Sowa
1473df80d93SArnaldo Carvalho de Melo if (sock_owned_by_user(sk))
1483df80d93SArnaldo Carvalho de Melo goto out;
1493df80d93SArnaldo Carvalho de Melo if ((1 << sk->sk_state) & (DCCPF_LISTEN | DCCPF_CLOSED))
1503df80d93SArnaldo Carvalho de Melo goto out;
1513df80d93SArnaldo Carvalho de Melo
15235ad9b9cSDavid S. Miller dst = inet6_csk_update_pmtu(sk, ntohl(info));
15335ad9b9cSDavid S. Miller if (!dst)
1543df80d93SArnaldo Carvalho de Melo goto out;
1553df80d93SArnaldo Carvalho de Melo
15635ad9b9cSDavid S. Miller if (inet_csk(sk)->icsk_pmtu_cookie > dst_mtu(dst))
1573df80d93SArnaldo Carvalho de Melo dccp_sync_mss(sk, dst_mtu(dst));
1583df80d93SArnaldo Carvalho de Melo goto out;
1593df80d93SArnaldo Carvalho de Melo }
1603df80d93SArnaldo Carvalho de Melo
1613df80d93SArnaldo Carvalho de Melo icmpv6_err_convert(type, code, &err);
1623df80d93SArnaldo Carvalho de Melo
1633df80d93SArnaldo Carvalho de Melo /* Might be for an request_sock */
1643df80d93SArnaldo Carvalho de Melo switch (sk->sk_state) {
1653df80d93SArnaldo Carvalho de Melo case DCCP_REQUESTING:
1663df80d93SArnaldo Carvalho de Melo case DCCP_RESPOND: /* Cannot happen.
1673df80d93SArnaldo Carvalho de Melo It can, it SYNs are crossed. --ANK */
1683df80d93SArnaldo Carvalho de Melo if (!sock_owned_by_user(sk)) {
169aa62d76bSEric Dumazet __DCCP_INC_STATS(DCCP_MIB_ATTEMPTFAILS);
1703df80d93SArnaldo Carvalho de Melo sk->sk_err = err;
1713df80d93SArnaldo Carvalho de Melo /*
1723df80d93SArnaldo Carvalho de Melo * Wake people up to see the error
1733df80d93SArnaldo Carvalho de Melo * (see connect in sock.c)
1743df80d93SArnaldo Carvalho de Melo */
175e3ae2365SAlexander Aring sk_error_report(sk);
1763df80d93SArnaldo Carvalho de Melo dccp_done(sk);
1779a25f0cbSEric Dumazet } else {
1789a25f0cbSEric Dumazet WRITE_ONCE(sk->sk_err_soft, err);
1799a25f0cbSEric Dumazet }
1803df80d93SArnaldo Carvalho de Melo goto out;
1813df80d93SArnaldo Carvalho de Melo }
1823df80d93SArnaldo Carvalho de Melo
1833df80d93SArnaldo Carvalho de Melo if (!sock_owned_by_user(sk) && np->recverr) {
1843df80d93SArnaldo Carvalho de Melo sk->sk_err = err;
185e3ae2365SAlexander Aring sk_error_report(sk);
1869a25f0cbSEric Dumazet } else {
1879a25f0cbSEric Dumazet WRITE_ONCE(sk->sk_err_soft, err);
1889a25f0cbSEric Dumazet }
1893df80d93SArnaldo Carvalho de Melo out:
1903df80d93SArnaldo Carvalho de Melo bh_unlock_sock(sk);
1913df80d93SArnaldo Carvalho de Melo sock_put(sk);
19232bbd879SStefano Brivio return 0;
1933df80d93SArnaldo Carvalho de Melo }
1943df80d93SArnaldo Carvalho de Melo
1953df80d93SArnaldo Carvalho de Melo
dccp_v6_send_response(const struct sock * sk,struct request_sock * req)196ea3bea3aSEric Dumazet static int dccp_v6_send_response(const struct sock *sk, struct request_sock *req)
1973df80d93SArnaldo Carvalho de Melo {
198634fb979SEric Dumazet struct inet_request_sock *ireq = inet_rsk(req);
1993df80d93SArnaldo Carvalho de Melo struct ipv6_pinfo *np = inet6_sk(sk);
2003df80d93SArnaldo Carvalho de Melo struct sk_buff *skb;
20120c59de2SArnaud Ebalard struct in6_addr *final_p, final;
2024c9483b2SDavid S. Miller struct flowi6 fl6;
2033df80d93SArnaldo Carvalho de Melo int err = -1;
204fd80eb94SDenis V. Lunev struct dst_entry *dst;
2053df80d93SArnaldo Carvalho de Melo
2064c9483b2SDavid S. Miller memset(&fl6, 0, sizeof(fl6));
2074c9483b2SDavid S. Miller fl6.flowi6_proto = IPPROTO_DCCP;
208634fb979SEric Dumazet fl6.daddr = ireq->ir_v6_rmt_addr;
209634fb979SEric Dumazet fl6.saddr = ireq->ir_v6_loc_addr;
2104c9483b2SDavid S. Miller fl6.flowlabel = 0;
211634fb979SEric Dumazet fl6.flowi6_oif = ireq->ir_iif;
212634fb979SEric Dumazet fl6.fl6_dport = ireq->ir_rmt_port;
213b44084c2SEric Dumazet fl6.fl6_sport = htons(ireq->ir_num);
2143df98d79SPaul Moore security_req_classify_flow(req, flowi6_to_flowi_common(&fl6));
2153df80d93SArnaldo Carvalho de Melo
2163df80d93SArnaldo Carvalho de Melo
21745f6fad8SEric Dumazet rcu_read_lock();
21845f6fad8SEric Dumazet final_p = fl6_update_dst(&fl6, rcu_dereference(np->opt), &final);
21945f6fad8SEric Dumazet rcu_read_unlock();
2203df80d93SArnaldo Carvalho de Melo
221c4e85f73SSabrina Dubroca dst = ip6_dst_lookup_flow(sock_net(sk), sk, &fl6, final_p);
22268d0c6d3SDavid S. Miller if (IS_ERR(dst)) {
22368d0c6d3SDavid S. Miller err = PTR_ERR(dst);
22468d0c6d3SDavid S. Miller dst = NULL;
2253df80d93SArnaldo Carvalho de Melo goto done;
22668d0c6d3SDavid S. Miller }
2273df80d93SArnaldo Carvalho de Melo
2283df80d93SArnaldo Carvalho de Melo skb = dccp_make_response(sk, dst, req);
2293df80d93SArnaldo Carvalho de Melo if (skb != NULL) {
2303df80d93SArnaldo Carvalho de Melo struct dccp_hdr *dh = dccp_hdr(skb);
23156ac42bcSHuw Davies struct ipv6_txoptions *opt;
23245329e71SArnaldo Carvalho de Melo
2336f4e5fffSGerrit Renker dh->dccph_checksum = dccp_v6_csum_finish(skb,
234634fb979SEric Dumazet &ireq->ir_v6_loc_addr,
235634fb979SEric Dumazet &ireq->ir_v6_rmt_addr);
236634fb979SEric Dumazet fl6.daddr = ireq->ir_v6_rmt_addr;
23745f6fad8SEric Dumazet rcu_read_lock();
23856ac42bcSHuw Davies opt = ireq->ipv6_opt;
23956ac42bcSHuw Davies if (!opt)
24056ac42bcSHuw Davies opt = rcu_dereference(np->opt);
2413c5b4d69SEric Dumazet err = ip6_xmit(sk, skb, &fl6, READ_ONCE(sk->sk_mark), opt,
2423c5b4d69SEric Dumazet np->tclass, sk->sk_priority);
24345f6fad8SEric Dumazet rcu_read_unlock();
244b9df3cb8SGerrit Renker err = net_xmit_eval(err);
2453df80d93SArnaldo Carvalho de Melo }
2463df80d93SArnaldo Carvalho de Melo
2473df80d93SArnaldo Carvalho de Melo done:
2480cbd7825SDavid S. Miller dst_release(dst);
2493df80d93SArnaldo Carvalho de Melo return err;
2503df80d93SArnaldo Carvalho de Melo }
2513df80d93SArnaldo Carvalho de Melo
dccp_v6_reqsk_destructor(struct request_sock * req)2523df80d93SArnaldo Carvalho de Melo static void dccp_v6_reqsk_destructor(struct request_sock *req)
2533df80d93SArnaldo Carvalho de Melo {
254d99a7bd2SGerrit Renker dccp_feat_list_purge(&dccp_rsk(req)->dreq_featneg);
25556ac42bcSHuw Davies kfree(inet_rsk(req)->ipv6_opt);
256634fb979SEric Dumazet kfree_skb(inet_rsk(req)->pktopts);
2573df80d93SArnaldo Carvalho de Melo }
2583df80d93SArnaldo Carvalho de Melo
dccp_v6_ctl_send_reset(const struct sock * sk,struct sk_buff * rxskb)259a00e7444SEric Dumazet static void dccp_v6_ctl_send_reset(const struct sock *sk, struct sk_buff *rxskb)
2603df80d93SArnaldo Carvalho de Melo {
261b71d1d42SEric Dumazet const struct ipv6hdr *rxip6h;
2623df80d93SArnaldo Carvalho de Melo struct sk_buff *skb;
2634c9483b2SDavid S. Miller struct flowi6 fl6;
264adf30907SEric Dumazet struct net *net = dev_net(skb_dst(rxskb)->dev);
265b98b3304SFlorian Westphal struct dccp_v6_pernet *pn;
266b98b3304SFlorian Westphal struct sock *ctl_sk;
267adf30907SEric Dumazet struct dst_entry *dst;
2683df80d93SArnaldo Carvalho de Melo
269e356d37aSGerrit Renker if (dccp_hdr(rxskb)->dccph_type == DCCP_PKT_RESET)
2703df80d93SArnaldo Carvalho de Melo return;
2713df80d93SArnaldo Carvalho de Melo
2723df80d93SArnaldo Carvalho de Melo if (!ipv6_unicast_destination(rxskb))
2733df80d93SArnaldo Carvalho de Melo return;
2743df80d93SArnaldo Carvalho de Melo
275b98b3304SFlorian Westphal pn = net_generic(net, dccp_v6_pernet_id);
276b98b3304SFlorian Westphal ctl_sk = pn->v6_ctl_sk;
27702047741SPavel Emelyanov skb = dccp_ctl_make_reset(ctl_sk, rxskb);
2783df80d93SArnaldo Carvalho de Melo if (skb == NULL)
2793df80d93SArnaldo Carvalho de Melo return;
2803df80d93SArnaldo Carvalho de Melo
2810660e03fSArnaldo Carvalho de Melo rxip6h = ipv6_hdr(rxskb);
282e356d37aSGerrit Renker dccp_hdr(skb)->dccph_checksum = dccp_v6_csum_finish(skb, &rxip6h->saddr,
2830660e03fSArnaldo Carvalho de Melo &rxip6h->daddr);
2846f4e5fffSGerrit Renker
2854c9483b2SDavid S. Miller memset(&fl6, 0, sizeof(fl6));
2864e3fd7a0SAlexey Dobriyan fl6.daddr = rxip6h->saddr;
2874e3fd7a0SAlexey Dobriyan fl6.saddr = rxip6h->daddr;
2886f4e5fffSGerrit Renker
2894c9483b2SDavid S. Miller fl6.flowi6_proto = IPPROTO_DCCP;
2904c9483b2SDavid S. Miller fl6.flowi6_oif = inet6_iif(rxskb);
2911958b856SDavid S. Miller fl6.fl6_dport = dccp_hdr(skb)->dccph_dport;
2921958b856SDavid S. Miller fl6.fl6_sport = dccp_hdr(skb)->dccph_sport;
2933df98d79SPaul Moore security_skb_classify_flow(rxskb, flowi6_to_flowi_common(&fl6));
2943df80d93SArnaldo Carvalho de Melo
2953df80d93SArnaldo Carvalho de Melo /* sk = NULL, but it is safe for now. RST socket required. */
296c4e85f73SSabrina Dubroca dst = ip6_dst_lookup_flow(sock_net(ctl_sk), ctl_sk, &fl6, NULL);
29768d0c6d3SDavid S. Miller if (!IS_ERR(dst)) {
298adf30907SEric Dumazet skb_dst_set(skb, dst);
2994f6570d7SEric Dumazet ip6_xmit(ctl_sk, skb, &fl6, 0, NULL, 0, 0);
3007309f882SEric Dumazet DCCP_INC_STATS(DCCP_MIB_OUTSEGS);
3017309f882SEric Dumazet DCCP_INC_STATS(DCCP_MIB_OUTRSTS);
3023df80d93SArnaldo Carvalho de Melo return;
3033df80d93SArnaldo Carvalho de Melo }
3043df80d93SArnaldo Carvalho de Melo
3053df80d93SArnaldo Carvalho de Melo kfree_skb(skb);
3063df80d93SArnaldo Carvalho de Melo }
3073df80d93SArnaldo Carvalho de Melo
30873c9e02cSGerrit Renker static struct request_sock_ops dccp6_request_sock_ops = {
30973c9e02cSGerrit Renker .family = AF_INET6,
31073c9e02cSGerrit Renker .obj_size = sizeof(struct dccp6_request_sock),
31173c9e02cSGerrit Renker .rtx_syn_ack = dccp_v6_send_response,
31273c9e02cSGerrit Renker .send_ack = dccp_reqsk_send_ack,
31373c9e02cSGerrit Renker .destructor = dccp_v6_reqsk_destructor,
31473c9e02cSGerrit Renker .send_reset = dccp_v6_ctl_send_reset,
315c72e1183SEric Dumazet .syn_ack_timeout = dccp_syn_ack_timeout,
31673c9e02cSGerrit Renker };
31773c9e02cSGerrit Renker
dccp_v6_conn_request(struct sock * sk,struct sk_buff * skb)3183df80d93SArnaldo Carvalho de Melo static int dccp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
3193df80d93SArnaldo Carvalho de Melo {
3203df80d93SArnaldo Carvalho de Melo struct request_sock *req;
3213df80d93SArnaldo Carvalho de Melo struct dccp_request_sock *dreq;
322634fb979SEric Dumazet struct inet_request_sock *ireq;
3233df80d93SArnaldo Carvalho de Melo struct ipv6_pinfo *np = inet6_sk(sk);
32460fe62e7SAndrea Bittau const __be32 service = dccp_hdr_request(skb)->dccph_req_service;
3253df80d93SArnaldo Carvalho de Melo struct dccp_skb_cb *dcb = DCCP_SKB_CB(skb);
3263df80d93SArnaldo Carvalho de Melo
3273df80d93SArnaldo Carvalho de Melo if (skb->protocol == htons(ETH_P_IP))
3283df80d93SArnaldo Carvalho de Melo return dccp_v4_conn_request(sk, skb);
3293df80d93SArnaldo Carvalho de Melo
3303df80d93SArnaldo Carvalho de Melo if (!ipv6_unicast_destination(skb))
3314a5409a5SGerrit Renker return 0; /* discard, don't send a reset here */
3323df80d93SArnaldo Carvalho de Melo
333dcc32f4fSJakub Kicinski if (ipv6_addr_v4mapped(&ipv6_hdr(skb)->saddr)) {
334dcc32f4fSJakub Kicinski __IP6_INC_STATS(sock_net(sk), NULL, IPSTATS_MIB_INHDRERRORS);
335dcc32f4fSJakub Kicinski return 0;
336dcc32f4fSJakub Kicinski }
337dcc32f4fSJakub Kicinski
3383df80d93SArnaldo Carvalho de Melo if (dccp_bad_service_code(sk, service)) {
3394a5409a5SGerrit Renker dcb->dccpd_reset_code = DCCP_RESET_CODE_BAD_SERVICE_CODE;
3403df80d93SArnaldo Carvalho de Melo goto drop;
3413df80d93SArnaldo Carvalho de Melo }
3423df80d93SArnaldo Carvalho de Melo /*
3433df80d93SArnaldo Carvalho de Melo * There are no SYN attacks on IPv6, yet...
3443df80d93SArnaldo Carvalho de Melo */
3454a5409a5SGerrit Renker dcb->dccpd_reset_code = DCCP_RESET_CODE_TOO_BUSY;
3463df80d93SArnaldo Carvalho de Melo if (inet_csk_reqsk_queue_is_full(sk))
3473df80d93SArnaldo Carvalho de Melo goto drop;
3483df80d93SArnaldo Carvalho de Melo
3495ea8ea2cSEric Dumazet if (sk_acceptq_is_full(sk))
3503df80d93SArnaldo Carvalho de Melo goto drop;
3513df80d93SArnaldo Carvalho de Melo
352a1a5344dSEric Dumazet req = inet_reqsk_alloc(&dccp6_request_sock_ops, sk, true);
3533df80d93SArnaldo Carvalho de Melo if (req == NULL)
3543df80d93SArnaldo Carvalho de Melo goto drop;
3553df80d93SArnaldo Carvalho de Melo
356ac75773cSGerrit Renker if (dccp_reqsk_init(req, dccp_sk(sk), skb))
357ac75773cSGerrit Renker goto drop_and_free;
3583df80d93SArnaldo Carvalho de Melo
3598b819412SGerrit Renker dreq = dccp_rsk(req);
3608b819412SGerrit Renker if (dccp_parse_options(sk, dreq, skb))
3618b819412SGerrit Renker goto drop_and_free;
3628b819412SGerrit Renker
363634fb979SEric Dumazet ireq = inet_rsk(req);
364634fb979SEric Dumazet ireq->ir_v6_rmt_addr = ipv6_hdr(skb)->saddr;
365634fb979SEric Dumazet ireq->ir_v6_loc_addr = ipv6_hdr(skb)->daddr;
3663f66b083SEric Dumazet ireq->ireq_family = AF_INET6;
367b855ff82SEric Dumazet ireq->ir_mark = inet_request_mark(sk, skb);
3683df80d93SArnaldo Carvalho de Melo
36982c0c8b9SKuniyuki Iwashima if (security_inet_conn_request(sk, skb, req))
37082c0c8b9SKuniyuki Iwashima goto drop_and_free;
37182c0c8b9SKuniyuki Iwashima
372a224772dSEric Dumazet if (ipv6_opt_accepted(sk, skb, IP6CB(skb)) ||
3733df80d93SArnaldo Carvalho de Melo np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo ||
3743df80d93SArnaldo Carvalho de Melo np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim) {
37563354797SReshetova, Elena refcount_inc(&skb->users);
376634fb979SEric Dumazet ireq->pktopts = skb;
3773df80d93SArnaldo Carvalho de Melo }
37836f7cec4SEric Dumazet ireq->ir_iif = READ_ONCE(sk->sk_bound_dev_if);
3793df80d93SArnaldo Carvalho de Melo
3803df80d93SArnaldo Carvalho de Melo /* So that link locals have meaning */
38136f7cec4SEric Dumazet if (!ireq->ir_iif &&
382634fb979SEric Dumazet ipv6_addr_type(&ireq->ir_v6_rmt_addr) & IPV6_ADDR_LINKLOCAL)
383634fb979SEric Dumazet ireq->ir_iif = inet6_iif(skb);
3843df80d93SArnaldo Carvalho de Melo
3853df80d93SArnaldo Carvalho de Melo /*
3863df80d93SArnaldo Carvalho de Melo * Step 3: Process LISTEN state
3873df80d93SArnaldo Carvalho de Melo *
3883df80d93SArnaldo Carvalho de Melo * Set S.ISR, S.GSR, S.SWL, S.SWH from packet or Init Cookie
3893df80d93SArnaldo Carvalho de Melo *
390f541fb7eSSamuel Jero * Setting S.SWL/S.SWH to is deferred to dccp_create_openreq_child().
3913df80d93SArnaldo Carvalho de Melo */
3923df80d93SArnaldo Carvalho de Melo dreq->dreq_isr = dcb->dccpd_seq;
393f541fb7eSSamuel Jero dreq->dreq_gsr = dreq->dreq_isr;
394865e9022SGerrit Renker dreq->dreq_iss = dccp_v6_init_sequence(skb);
395f541fb7eSSamuel Jero dreq->dreq_gss = dreq->dreq_iss;
3963df80d93SArnaldo Carvalho de Melo dreq->dreq_service = service;
3973df80d93SArnaldo Carvalho de Melo
3981a2c6181SChristoph Paasch if (dccp_v6_send_response(sk, req))
3993df80d93SArnaldo Carvalho de Melo goto drop_and_free;
4003df80d93SArnaldo Carvalho de Melo
401fdae4d13Sluoxuanqiang if (unlikely(!inet_csk_reqsk_queue_hash_add(sk, req, DCCP_TIMEOUT_INIT)))
402fdae4d13Sluoxuanqiang reqsk_free(req);
403fdae4d13Sluoxuanqiang else
4040c2232b0SXin Long reqsk_put(req);
405fdae4d13Sluoxuanqiang
4063df80d93SArnaldo Carvalho de Melo return 0;
4073df80d93SArnaldo Carvalho de Melo
4083df80d93SArnaldo Carvalho de Melo drop_and_free:
4093df80d93SArnaldo Carvalho de Melo reqsk_free(req);
4103df80d93SArnaldo Carvalho de Melo drop:
411aa62d76bSEric Dumazet __DCCP_INC_STATS(DCCP_MIB_ATTEMPTFAILS);
4123df80d93SArnaldo Carvalho de Melo return -1;
4133df80d93SArnaldo Carvalho de Melo }
4143df80d93SArnaldo Carvalho de Melo
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)4150c27171eSEric Dumazet static struct sock *dccp_v6_request_recv_sock(const struct sock *sk,
4163df80d93SArnaldo Carvalho de Melo struct sk_buff *skb,
4173df80d93SArnaldo Carvalho de Melo struct request_sock *req,
4185e0724d0SEric Dumazet struct dst_entry *dst,
4195e0724d0SEric Dumazet struct request_sock *req_unhash,
4205e0724d0SEric Dumazet bool *own_req)
4213df80d93SArnaldo Carvalho de Melo {
422634fb979SEric Dumazet struct inet_request_sock *ireq = inet_rsk(req);
4230c27171eSEric Dumazet struct ipv6_pinfo *newnp;
4240c27171eSEric Dumazet const struct ipv6_pinfo *np = inet6_sk(sk);
42545f6fad8SEric Dumazet struct ipv6_txoptions *opt;
4263df80d93SArnaldo Carvalho de Melo struct inet_sock *newinet;
4273df80d93SArnaldo Carvalho de Melo struct dccp6_sock *newdp6;
4283df80d93SArnaldo Carvalho de Melo struct sock *newsk;
4293df80d93SArnaldo Carvalho de Melo
4303df80d93SArnaldo Carvalho de Melo if (skb->protocol == htons(ETH_P_IP)) {
4313df80d93SArnaldo Carvalho de Melo /*
4323df80d93SArnaldo Carvalho de Melo * v6 mapped
4333df80d93SArnaldo Carvalho de Melo */
4345e0724d0SEric Dumazet newsk = dccp_v4_request_recv_sock(sk, skb, req, dst,
4355e0724d0SEric Dumazet req_unhash, own_req);
4363df80d93SArnaldo Carvalho de Melo if (newsk == NULL)
4373df80d93SArnaldo Carvalho de Melo return NULL;
4383df80d93SArnaldo Carvalho de Melo
4393df80d93SArnaldo Carvalho de Melo newdp6 = (struct dccp6_sock *)newsk;
4403df80d93SArnaldo Carvalho de Melo newinet = inet_sk(newsk);
4413df80d93SArnaldo Carvalho de Melo newinet->pinet6 = &newdp6->inet6;
4423df80d93SArnaldo Carvalho de Melo newnp = inet6_sk(newsk);
4433df80d93SArnaldo Carvalho de Melo
4443df80d93SArnaldo Carvalho de Melo memcpy(newnp, np, sizeof(struct ipv6_pinfo));
4453df80d93SArnaldo Carvalho de Melo
446d1e559d0SEric Dumazet newnp->saddr = newsk->sk_v6_rcv_saddr;
4473df80d93SArnaldo Carvalho de Melo
4483df80d93SArnaldo Carvalho de Melo inet_csk(newsk)->icsk_af_ops = &dccp_ipv6_mapped;
4493df80d93SArnaldo Carvalho de Melo newsk->sk_backlog_rcv = dccp_v4_do_rcv;
4503df80d93SArnaldo Carvalho de Melo newnp->pktoptions = NULL;
4513df80d93SArnaldo Carvalho de Melo newnp->opt = NULL;
45283eaddabSWANG Cong newnp->ipv6_mc_list = NULL;
45383eaddabSWANG Cong newnp->ipv6_ac_list = NULL;
45483eaddabSWANG Cong newnp->ipv6_fl_list = NULL;
455e0aa6770SEric Dumazet newnp->mcast_oif = inet_iif(skb);
456e0aa6770SEric Dumazet newnp->mcast_hops = ip_hdr(skb)->ttl;
4573df80d93SArnaldo Carvalho de Melo
4583df80d93SArnaldo Carvalho de Melo /*
4593df80d93SArnaldo Carvalho de Melo * No need to charge this sock to the relevant IPv6 refcnt debug socks count
4603df80d93SArnaldo Carvalho de Melo * here, dccp_create_openreq_child now does this for us, see the comment in
4613df80d93SArnaldo Carvalho de Melo * that function for the gory details. -acme
4623df80d93SArnaldo Carvalho de Melo */
4633df80d93SArnaldo Carvalho de Melo
4643df80d93SArnaldo Carvalho de Melo /* It is tricky place. Until this moment IPv4 tcp
4653df80d93SArnaldo Carvalho de Melo worked with IPv6 icsk.icsk_af_ops.
4663df80d93SArnaldo Carvalho de Melo Sync it now.
4673df80d93SArnaldo Carvalho de Melo */
468d83d8461SArnaldo Carvalho de Melo dccp_sync_mss(newsk, inet_csk(newsk)->icsk_pmtu_cookie);
4693df80d93SArnaldo Carvalho de Melo
4703df80d93SArnaldo Carvalho de Melo return newsk;
4713df80d93SArnaldo Carvalho de Melo }
4723df80d93SArnaldo Carvalho de Melo
4733df80d93SArnaldo Carvalho de Melo
4743df80d93SArnaldo Carvalho de Melo if (sk_acceptq_is_full(sk))
4753df80d93SArnaldo Carvalho de Melo goto out_overflow;
4763df80d93SArnaldo Carvalho de Melo
477f76b33c3SEric Dumazet if (!dst) {
4784c9483b2SDavid S. Miller struct flowi6 fl6;
4793df80d93SArnaldo Carvalho de Melo
480f76b33c3SEric Dumazet dst = inet6_csk_route_req(sk, &fl6, req, IPPROTO_DCCP);
481f76b33c3SEric Dumazet if (!dst)
4823df80d93SArnaldo Carvalho de Melo goto out;
4833df80d93SArnaldo Carvalho de Melo }
4843df80d93SArnaldo Carvalho de Melo
4853df80d93SArnaldo Carvalho de Melo newsk = dccp_create_openreq_child(sk, req, skb);
4863df80d93SArnaldo Carvalho de Melo if (newsk == NULL)
487093d2823SBalazs Scheidler goto out_nonewsk;
4883df80d93SArnaldo Carvalho de Melo
4893df80d93SArnaldo Carvalho de Melo /*
4903df80d93SArnaldo Carvalho de Melo * No need to charge this sock to the relevant IPv6 refcnt debug socks
4913df80d93SArnaldo Carvalho de Melo * count here, dccp_create_openreq_child now does this for us, see the
4923df80d93SArnaldo Carvalho de Melo * comment in that function for the gory details. -acme
4933df80d93SArnaldo Carvalho de Melo */
4943df80d93SArnaldo Carvalho de Melo
4956bd4f355SEric Dumazet ip6_dst_store(newsk, dst, NULL, NULL);
49645329e71SArnaldo Carvalho de Melo newsk->sk_route_caps = dst->dev->features & ~(NETIF_F_IP_CSUM |
49745329e71SArnaldo Carvalho de Melo NETIF_F_TSO);
4983df80d93SArnaldo Carvalho de Melo newdp6 = (struct dccp6_sock *)newsk;
4993df80d93SArnaldo Carvalho de Melo newinet = inet_sk(newsk);
5003df80d93SArnaldo Carvalho de Melo newinet->pinet6 = &newdp6->inet6;
5013df80d93SArnaldo Carvalho de Melo newnp = inet6_sk(newsk);
5023df80d93SArnaldo Carvalho de Melo
5033df80d93SArnaldo Carvalho de Melo memcpy(newnp, np, sizeof(struct ipv6_pinfo));
5043df80d93SArnaldo Carvalho de Melo
505634fb979SEric Dumazet newsk->sk_v6_daddr = ireq->ir_v6_rmt_addr;
506634fb979SEric Dumazet newnp->saddr = ireq->ir_v6_loc_addr;
507634fb979SEric Dumazet newsk->sk_v6_rcv_saddr = ireq->ir_v6_loc_addr;
508634fb979SEric Dumazet newsk->sk_bound_dev_if = ireq->ir_iif;
5093df80d93SArnaldo Carvalho de Melo
5103df80d93SArnaldo Carvalho de Melo /* Now IPv6 options...
5113df80d93SArnaldo Carvalho de Melo
5123df80d93SArnaldo Carvalho de Melo First: no IPv4 options.
5133df80d93SArnaldo Carvalho de Melo */
514f6d8bd05SEric Dumazet newinet->inet_opt = NULL;
5153df80d93SArnaldo Carvalho de Melo
5163df80d93SArnaldo Carvalho de Melo /* Clone RX bits */
5173df80d93SArnaldo Carvalho de Melo newnp->rxopt.all = np->rxopt.all;
5183df80d93SArnaldo Carvalho de Melo
51983eaddabSWANG Cong newnp->ipv6_mc_list = NULL;
52083eaddabSWANG Cong newnp->ipv6_ac_list = NULL;
52183eaddabSWANG Cong newnp->ipv6_fl_list = NULL;
5223df80d93SArnaldo Carvalho de Melo newnp->pktoptions = NULL;
5233df80d93SArnaldo Carvalho de Melo newnp->opt = NULL;
5243df80d93SArnaldo Carvalho de Melo newnp->mcast_oif = inet6_iif(skb);
5250660e03fSArnaldo Carvalho de Melo newnp->mcast_hops = ipv6_hdr(skb)->hop_limit;
5263df80d93SArnaldo Carvalho de Melo
52745329e71SArnaldo Carvalho de Melo /*
52845329e71SArnaldo Carvalho de Melo * Clone native IPv6 options from listening socket (if any)
52945329e71SArnaldo Carvalho de Melo *
53045329e71SArnaldo Carvalho de Melo * Yes, keeping reference count would be much more clever, but we make
53145329e71SArnaldo Carvalho de Melo * one more one thing there: reattach optmem to newsk.
5323df80d93SArnaldo Carvalho de Melo */
53356ac42bcSHuw Davies opt = ireq->ipv6_opt;
53456ac42bcSHuw Davies if (!opt)
53545f6fad8SEric Dumazet opt = rcu_dereference(np->opt);
53645f6fad8SEric Dumazet if (opt) {
53745f6fad8SEric Dumazet opt = ipv6_dup_options(newsk, opt);
53845f6fad8SEric Dumazet RCU_INIT_POINTER(newnp->opt, opt);
53945f6fad8SEric Dumazet }
540d83d8461SArnaldo Carvalho de Melo inet_csk(newsk)->icsk_ext_hdr_len = 0;
54145f6fad8SEric Dumazet if (opt)
54245f6fad8SEric Dumazet inet_csk(newsk)->icsk_ext_hdr_len = opt->opt_nflen +
54345f6fad8SEric Dumazet opt->opt_flen;
5443df80d93SArnaldo Carvalho de Melo
5453df80d93SArnaldo Carvalho de Melo dccp_sync_mss(newsk, dst_mtu(dst));
5463df80d93SArnaldo Carvalho de Melo
547c720c7e8SEric Dumazet newinet->inet_daddr = newinet->inet_saddr = LOOPBACK4_IPV6;
548c720c7e8SEric Dumazet newinet->inet_rcv_saddr = LOOPBACK4_IPV6;
5493df80d93SArnaldo Carvalho de Melo
550093d2823SBalazs Scheidler if (__inet_inherit_port(sk, newsk) < 0) {
551e337e24dSChristoph Paasch inet_csk_prepare_forced_close(newsk);
552e337e24dSChristoph Paasch dccp_done(newsk);
553093d2823SBalazs Scheidler goto out;
554093d2823SBalazs Scheidler }
55501770a16SRicardo Dias *own_req = inet_ehash_nolisten(newsk, req_to_sk(req_unhash), NULL);
556ce105008SEric Dumazet /* Clone pktoptions received with SYN, if we own the req */
557ce105008SEric Dumazet if (*own_req && ireq->pktopts) {
558ca43ccf4SKuniyuki Iwashima newnp->pktoptions = skb_clone_and_charge_r(ireq->pktopts, newsk);
559ce105008SEric Dumazet consume_skb(ireq->pktopts);
560ce105008SEric Dumazet ireq->pktopts = NULL;
561ce105008SEric Dumazet }
5623df80d93SArnaldo Carvalho de Melo
5633df80d93SArnaldo Carvalho de Melo return newsk;
5643df80d93SArnaldo Carvalho de Melo
5653df80d93SArnaldo Carvalho de Melo out_overflow:
56602a1d6e7SEric Dumazet __NET_INC_STATS(sock_net(sk), LINUX_MIB_LISTENOVERFLOWS);
567093d2823SBalazs Scheidler out_nonewsk:
568093d2823SBalazs Scheidler dst_release(dst);
5693df80d93SArnaldo Carvalho de Melo out:
57002a1d6e7SEric Dumazet __NET_INC_STATS(sock_net(sk), LINUX_MIB_LISTENDROPS);
5713df80d93SArnaldo Carvalho de Melo return NULL;
5723df80d93SArnaldo Carvalho de Melo }
5733df80d93SArnaldo Carvalho de Melo
5743df80d93SArnaldo Carvalho de Melo /* The socket must have it's spinlock held when we get
5753df80d93SArnaldo Carvalho de Melo * here.
5763df80d93SArnaldo Carvalho de Melo *
5773df80d93SArnaldo Carvalho de Melo * We have a potential double-lock case here, so even when
5783df80d93SArnaldo Carvalho de Melo * doing backlog processing we use the BH locking scheme.
5793df80d93SArnaldo Carvalho de Melo * This is because we cannot sleep with the original spinlock
5803df80d93SArnaldo Carvalho de Melo * held.
5813df80d93SArnaldo Carvalho de Melo */
dccp_v6_do_rcv(struct sock * sk,struct sk_buff * skb)5823df80d93SArnaldo Carvalho de Melo static int dccp_v6_do_rcv(struct sock *sk, struct sk_buff *skb)
5833df80d93SArnaldo Carvalho de Melo {
5843df80d93SArnaldo Carvalho de Melo struct ipv6_pinfo *np = inet6_sk(sk);
5853df80d93SArnaldo Carvalho de Melo struct sk_buff *opt_skb = NULL;
5863df80d93SArnaldo Carvalho de Melo
5873df80d93SArnaldo Carvalho de Melo /* Imagine: socket is IPv6. IPv4 packet arrives,
5883df80d93SArnaldo Carvalho de Melo goes to IPv4 receive handler and backlogged.
5893df80d93SArnaldo Carvalho de Melo From backlog it always goes here. Kerboom...
5903df80d93SArnaldo Carvalho de Melo Fortunately, dccp_rcv_established and rcv_established
5913df80d93SArnaldo Carvalho de Melo handle them correctly, but it is not case with
5923df80d93SArnaldo Carvalho de Melo dccp_v6_hnd_req and dccp_v6_ctl_send_reset(). --ANK
5933df80d93SArnaldo Carvalho de Melo */
5943df80d93SArnaldo Carvalho de Melo
5953df80d93SArnaldo Carvalho de Melo if (skb->protocol == htons(ETH_P_IP))
5963df80d93SArnaldo Carvalho de Melo return dccp_v4_do_rcv(sk, skb);
5973df80d93SArnaldo Carvalho de Melo
598fda9ef5dSDmitry Mishin if (sk_filter(sk, skb))
5993df80d93SArnaldo Carvalho de Melo goto discard;
6003df80d93SArnaldo Carvalho de Melo
6013df80d93SArnaldo Carvalho de Melo /*
60245329e71SArnaldo Carvalho de Melo * socket locking is here for SMP purposes as backlog rcv is currently
60345329e71SArnaldo Carvalho de Melo * called with bh processing disabled.
6043df80d93SArnaldo Carvalho de Melo */
6053df80d93SArnaldo Carvalho de Melo
6063df80d93SArnaldo Carvalho de Melo /* Do Stevens' IPV6_PKTOPTIONS.
6073df80d93SArnaldo Carvalho de Melo
6083df80d93SArnaldo Carvalho de Melo Yes, guys, it is the only place in our code, where we
6093df80d93SArnaldo Carvalho de Melo may make it not affecting IPv4.
6103df80d93SArnaldo Carvalho de Melo The rest of code is protocol independent,
6113df80d93SArnaldo Carvalho de Melo and I do not like idea to uglify IPv4.
6123df80d93SArnaldo Carvalho de Melo
6133df80d93SArnaldo Carvalho de Melo Actually, all the idea behind IPV6_PKTOPTIONS
6143df80d93SArnaldo Carvalho de Melo looks not very well thought. For now we latch
6153df80d93SArnaldo Carvalho de Melo options, received in the last packet, enqueued
6163df80d93SArnaldo Carvalho de Melo by tcp. Feel free to propose better solution.
6173df80d93SArnaldo Carvalho de Melo --ANK (980728)
6183df80d93SArnaldo Carvalho de Melo */
619*3f51f8c9SWang Liang if (np->rxopt.all && sk->sk_state != DCCP_LISTEN)
620ca43ccf4SKuniyuki Iwashima opt_skb = skb_clone_and_charge_r(skb, sk);
6213df80d93SArnaldo Carvalho de Melo
6223df80d93SArnaldo Carvalho de Melo if (sk->sk_state == DCCP_OPEN) { /* Fast path */
6233df80d93SArnaldo Carvalho de Melo if (dccp_rcv_established(sk, skb, dccp_hdr(skb), skb->len))
6243df80d93SArnaldo Carvalho de Melo goto reset;
625323fbd0eSAndrii if (opt_skb)
626323fbd0eSAndrii goto ipv6_pktoptions;
6273df80d93SArnaldo Carvalho de Melo return 0;
6283df80d93SArnaldo Carvalho de Melo }
6293df80d93SArnaldo Carvalho de Melo
630d83ca5acSGerrit Renker /*
631d83ca5acSGerrit Renker * Step 3: Process LISTEN state
632d83ca5acSGerrit Renker * If S.state == LISTEN,
633d83ca5acSGerrit Renker * If P.type == Request or P contains a valid Init Cookie option,
634d83ca5acSGerrit Renker * (* Must scan the packet's options to check for Init
635d83ca5acSGerrit Renker * Cookies. Only Init Cookies are processed here,
636d83ca5acSGerrit Renker * however; other options are processed in Step 8. This
637d83ca5acSGerrit Renker * scan need only be performed if the endpoint uses Init
638d83ca5acSGerrit Renker * Cookies *)
639d83ca5acSGerrit Renker * (* Generate a new socket and switch to that socket *)
640d83ca5acSGerrit Renker * Set S := new socket for this port pair
641d83ca5acSGerrit Renker * S.state = RESPOND
642d83ca5acSGerrit Renker * Choose S.ISS (initial seqno) or set from Init Cookies
643d83ca5acSGerrit Renker * Initialize S.GAR := S.ISS
644d83ca5acSGerrit Renker * Set S.ISR, S.GSR, S.SWL, S.SWH from packet or Init Cookies
645d83ca5acSGerrit Renker * Continue with S.state == RESPOND
646d83ca5acSGerrit Renker * (* A Response packet will be generated in Step 11 *)
647d83ca5acSGerrit Renker * Otherwise,
648d83ca5acSGerrit Renker * Generate Reset(No Connection) unless P.type == Reset
649d83ca5acSGerrit Renker * Drop packet and return
650d83ca5acSGerrit Renker *
651d83ca5acSGerrit Renker * NOTE: the check for the packet types is done in
652d83ca5acSGerrit Renker * dccp_rcv_state_process
653d83ca5acSGerrit Renker */
6543df80d93SArnaldo Carvalho de Melo
6553df80d93SArnaldo Carvalho de Melo if (dccp_rcv_state_process(sk, skb, dccp_hdr(skb), skb->len))
6563df80d93SArnaldo Carvalho de Melo goto reset;
657323fbd0eSAndrii if (opt_skb)
658323fbd0eSAndrii goto ipv6_pktoptions;
6593df80d93SArnaldo Carvalho de Melo return 0;
6603df80d93SArnaldo Carvalho de Melo
6613df80d93SArnaldo Carvalho de Melo reset:
662cfb6eeb4SYOSHIFUJI Hideaki dccp_v6_ctl_send_reset(sk, skb);
6633df80d93SArnaldo Carvalho de Melo discard:
66445329e71SArnaldo Carvalho de Melo if (opt_skb != NULL)
6653df80d93SArnaldo Carvalho de Melo __kfree_skb(opt_skb);
6663df80d93SArnaldo Carvalho de Melo kfree_skb(skb);
6673df80d93SArnaldo Carvalho de Melo return 0;
668323fbd0eSAndrii
669323fbd0eSAndrii /* Handling IPV6_PKTOPTIONS skb the similar
670323fbd0eSAndrii * way it's done for net/ipv6/tcp_ipv6.c
671323fbd0eSAndrii */
672323fbd0eSAndrii ipv6_pktoptions:
673323fbd0eSAndrii if (!((1 << sk->sk_state) & (DCCPF_CLOSED | DCCPF_LISTEN))) {
674323fbd0eSAndrii if (np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo)
675323fbd0eSAndrii np->mcast_oif = inet6_iif(opt_skb);
676323fbd0eSAndrii if (np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim)
677323fbd0eSAndrii np->mcast_hops = ipv6_hdr(opt_skb)->hop_limit;
678323fbd0eSAndrii if (np->rxopt.bits.rxflow || np->rxopt.bits.rxtclass)
679323fbd0eSAndrii np->rcv_flowinfo = ip6_flowinfo(ipv6_hdr(opt_skb));
680323fbd0eSAndrii if (np->repflow)
681323fbd0eSAndrii np->flow_label = ip6_flowlabel(ipv6_hdr(opt_skb));
682323fbd0eSAndrii if (ipv6_opt_accepted(sk, opt_skb,
683323fbd0eSAndrii &DCCP_SKB_CB(opt_skb)->header.h6)) {
684323fbd0eSAndrii memmove(IP6CB(opt_skb),
685323fbd0eSAndrii &DCCP_SKB_CB(opt_skb)->header.h6,
686323fbd0eSAndrii sizeof(struct inet6_skb_parm));
687323fbd0eSAndrii opt_skb = xchg(&np->pktoptions, opt_skb);
688323fbd0eSAndrii } else {
689323fbd0eSAndrii __kfree_skb(opt_skb);
690323fbd0eSAndrii opt_skb = xchg(&np->pktoptions, NULL);
691323fbd0eSAndrii }
692323fbd0eSAndrii }
693323fbd0eSAndrii
694323fbd0eSAndrii kfree_skb(opt_skb);
695323fbd0eSAndrii return 0;
6963df80d93SArnaldo Carvalho de Melo }
6973df80d93SArnaldo Carvalho de Melo
dccp_v6_rcv(struct sk_buff * skb)698e5bbef20SHerbert Xu static int dccp_v6_rcv(struct sk_buff *skb)
6993df80d93SArnaldo Carvalho de Melo {
7003df80d93SArnaldo Carvalho de Melo const struct dccp_hdr *dh;
7013b24d854SEric Dumazet bool refcounted;
7023df80d93SArnaldo Carvalho de Melo struct sock *sk;
7036f4e5fffSGerrit Renker int min_cov;
7043df80d93SArnaldo Carvalho de Melo
7056f4e5fffSGerrit Renker /* Step 1: Check header basics */
7063df80d93SArnaldo Carvalho de Melo
7073df80d93SArnaldo Carvalho de Melo if (dccp_invalid_packet(skb))
7083df80d93SArnaldo Carvalho de Melo goto discard_it;
7093df80d93SArnaldo Carvalho de Melo
7106f4e5fffSGerrit Renker /* Step 1: If header checksum is incorrect, drop packet and return. */
7110660e03fSArnaldo Carvalho de Melo if (dccp_v6_csum_finish(skb, &ipv6_hdr(skb)->saddr,
7120660e03fSArnaldo Carvalho de Melo &ipv6_hdr(skb)->daddr)) {
71359348b19SGerrit Renker DCCP_WARN("dropped packet with invalid checksum\n");
7146f4e5fffSGerrit Renker goto discard_it;
7156f4e5fffSGerrit Renker }
7166f4e5fffSGerrit Renker
7173df80d93SArnaldo Carvalho de Melo dh = dccp_hdr(skb);
7183df80d93SArnaldo Carvalho de Melo
719fde20105SGerrit Renker DCCP_SKB_CB(skb)->dccpd_seq = dccp_hdr_seq(dh);
7203df80d93SArnaldo Carvalho de Melo DCCP_SKB_CB(skb)->dccpd_type = dh->dccph_type;
7213df80d93SArnaldo Carvalho de Melo
7223df80d93SArnaldo Carvalho de Melo if (dccp_packet_without_ack(skb))
7233df80d93SArnaldo Carvalho de Melo DCCP_SKB_CB(skb)->dccpd_ack_seq = DCCP_PKT_WITHOUT_ACK_SEQ;
7243df80d93SArnaldo Carvalho de Melo else
7253df80d93SArnaldo Carvalho de Melo DCCP_SKB_CB(skb)->dccpd_ack_seq = dccp_hdr_ack_seq(skb);
7263df80d93SArnaldo Carvalho de Melo
7274bdc3d66SEric Dumazet lookup:
728a583636aSCraig Gallek sk = __inet6_lookup_skb(&dccp_hashinfo, skb, __dccp_hdr_len(dh),
729870c3151SEric Dumazet dh->dccph_sport, dh->dccph_dport,
7304297a0efSDavid Ahern inet6_iif(skb), 0, &refcounted);
7314bdc3d66SEric Dumazet if (!sk) {
732d23c7107SGerrit Renker dccp_pr_debug("failed to look up flow ID in table and "
733d23c7107SGerrit Renker "get corresponding socket\n");
7343df80d93SArnaldo Carvalho de Melo goto no_dccp_socket;
735d23c7107SGerrit Renker }
7363df80d93SArnaldo Carvalho de Melo
7373df80d93SArnaldo Carvalho de Melo /*
7383df80d93SArnaldo Carvalho de Melo * Step 2:
7393df80d93SArnaldo Carvalho de Melo * ... or S.state == TIMEWAIT,
7403df80d93SArnaldo Carvalho de Melo * Generate Reset(No Connection) unless P.type == Reset
7413df80d93SArnaldo Carvalho de Melo * Drop packet and return
7423df80d93SArnaldo Carvalho de Melo */
743d23c7107SGerrit Renker if (sk->sk_state == DCCP_TIME_WAIT) {
744d23c7107SGerrit Renker dccp_pr_debug("sk->sk_state == DCCP_TIME_WAIT: do_time_wait\n");
745d23c7107SGerrit Renker inet_twsk_put(inet_twsk(sk));
746d23c7107SGerrit Renker goto no_dccp_socket;
747d23c7107SGerrit Renker }
7483df80d93SArnaldo Carvalho de Melo
749079096f1SEric Dumazet if (sk->sk_state == DCCP_NEW_SYN_RECV) {
750079096f1SEric Dumazet struct request_sock *req = inet_reqsk(sk);
7517716682cSEric Dumazet struct sock *nsk;
752079096f1SEric Dumazet
753079096f1SEric Dumazet sk = req->rsk_listener;
7547716682cSEric Dumazet if (unlikely(sk->sk_state != DCCP_LISTEN)) {
755f03f2e15SEric Dumazet inet_csk_reqsk_queue_drop_and_put(sk, req);
7564bdc3d66SEric Dumazet goto lookup;
7574bdc3d66SEric Dumazet }
7587716682cSEric Dumazet sock_hold(sk);
7593b24d854SEric Dumazet refcounted = true;
7607716682cSEric Dumazet nsk = dccp_check_req(sk, skb, req);
761079096f1SEric Dumazet if (!nsk) {
762079096f1SEric Dumazet reqsk_put(req);
7637716682cSEric Dumazet goto discard_and_relse;
764079096f1SEric Dumazet }
765079096f1SEric Dumazet if (nsk == sk) {
766079096f1SEric Dumazet reqsk_put(req);
767079096f1SEric Dumazet } else if (dccp_child_process(sk, nsk, skb)) {
768079096f1SEric Dumazet dccp_v6_ctl_send_reset(sk, skb);
7697716682cSEric Dumazet goto discard_and_relse;
770079096f1SEric Dumazet } else {
7717716682cSEric Dumazet sock_put(sk);
772079096f1SEric Dumazet return 0;
773079096f1SEric Dumazet }
774079096f1SEric Dumazet }
7756f4e5fffSGerrit Renker /*
7766f4e5fffSGerrit Renker * RFC 4340, sec. 9.2.1: Minimum Checksum Coverage
7776f4e5fffSGerrit Renker * o if MinCsCov = 0, only packets with CsCov = 0 are accepted
7786f4e5fffSGerrit Renker * o if MinCsCov > 0, also accept packets with CsCov >= MinCsCov
7796f4e5fffSGerrit Renker */
7806f4e5fffSGerrit Renker min_cov = dccp_sk(sk)->dccps_pcrlen;
7816f4e5fffSGerrit Renker if (dh->dccph_cscov && (min_cov == 0 || dh->dccph_cscov < min_cov)) {
7826f4e5fffSGerrit Renker dccp_pr_debug("Packet CsCov %d does not satisfy MinCsCov %d\n",
7836f4e5fffSGerrit Renker dh->dccph_cscov, min_cov);
7846f4e5fffSGerrit Renker /* FIXME: send Data Dropped option (see also dccp_v4_rcv) */
7856f4e5fffSGerrit Renker goto discard_and_relse;
7866f4e5fffSGerrit Renker }
7876f4e5fffSGerrit Renker
7883df80d93SArnaldo Carvalho de Melo if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb))
7893df80d93SArnaldo Carvalho de Melo goto discard_and_relse;
790b0e214d2SMadhu Koriginja nf_reset_ct(skb);
7913df80d93SArnaldo Carvalho de Melo
792c3f24cfbSEric Dumazet return __sk_receive_skb(sk, skb, 1, dh->dccph_doff * 4,
793c3f24cfbSEric Dumazet refcounted) ? -1 : 0;
7943df80d93SArnaldo Carvalho de Melo
7953df80d93SArnaldo Carvalho de Melo no_dccp_socket:
7963df80d93SArnaldo Carvalho de Melo if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb))
7973df80d93SArnaldo Carvalho de Melo goto discard_it;
7983df80d93SArnaldo Carvalho de Melo /*
7993df80d93SArnaldo Carvalho de Melo * Step 2:
800d83ca5acSGerrit Renker * If no socket ...
8013df80d93SArnaldo Carvalho de Melo * Generate Reset(No Connection) unless P.type == Reset
8023df80d93SArnaldo Carvalho de Melo * Drop packet and return
8033df80d93SArnaldo Carvalho de Melo */
8043df80d93SArnaldo Carvalho de Melo if (dh->dccph_type != DCCP_PKT_RESET) {
8053df80d93SArnaldo Carvalho de Melo DCCP_SKB_CB(skb)->dccpd_reset_code =
8063df80d93SArnaldo Carvalho de Melo DCCP_RESET_CODE_NO_CONNECTION;
807cfb6eeb4SYOSHIFUJI Hideaki dccp_v6_ctl_send_reset(sk, skb);
8083df80d93SArnaldo Carvalho de Melo }
809d23c7107SGerrit Renker
8103df80d93SArnaldo Carvalho de Melo discard_it:
8113df80d93SArnaldo Carvalho de Melo kfree_skb(skb);
8123df80d93SArnaldo Carvalho de Melo return 0;
8133df80d93SArnaldo Carvalho de Melo
8143df80d93SArnaldo Carvalho de Melo discard_and_relse:
8153b24d854SEric Dumazet if (refcounted)
8163df80d93SArnaldo Carvalho de Melo sock_put(sk);
8173df80d93SArnaldo Carvalho de Melo goto discard_it;
8183df80d93SArnaldo Carvalho de Melo }
8193df80d93SArnaldo Carvalho de Melo
dccp_v6_connect(struct sock * sk,struct sockaddr * uaddr,int addr_len)82073c9e02cSGerrit Renker static int dccp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
82173c9e02cSGerrit Renker int addr_len)
82273c9e02cSGerrit Renker {
82373c9e02cSGerrit Renker struct sockaddr_in6 *usin = (struct sockaddr_in6 *)uaddr;
82473c9e02cSGerrit Renker struct inet_connection_sock *icsk = inet_csk(sk);
82573c9e02cSGerrit Renker struct inet_sock *inet = inet_sk(sk);
82673c9e02cSGerrit Renker struct ipv6_pinfo *np = inet6_sk(sk);
82773c9e02cSGerrit Renker struct dccp_sock *dp = dccp_sk(sk);
82820c59de2SArnaud Ebalard struct in6_addr *saddr = NULL, *final_p, final;
82945f6fad8SEric Dumazet struct ipv6_txoptions *opt;
8304c9483b2SDavid S. Miller struct flowi6 fl6;
83173c9e02cSGerrit Renker struct dst_entry *dst;
83273c9e02cSGerrit Renker int addr_type;
83373c9e02cSGerrit Renker int err;
83473c9e02cSGerrit Renker
83573c9e02cSGerrit Renker dp->dccps_role = DCCP_ROLE_CLIENT;
83673c9e02cSGerrit Renker
83773c9e02cSGerrit Renker if (addr_len < SIN6_LEN_RFC2133)
83873c9e02cSGerrit Renker return -EINVAL;
83973c9e02cSGerrit Renker
84073c9e02cSGerrit Renker if (usin->sin6_family != AF_INET6)
84173c9e02cSGerrit Renker return -EAFNOSUPPORT;
84273c9e02cSGerrit Renker
8434c9483b2SDavid S. Miller memset(&fl6, 0, sizeof(fl6));
84473c9e02cSGerrit Renker
84573c9e02cSGerrit Renker if (np->sndflow) {
8464c9483b2SDavid S. Miller fl6.flowlabel = usin->sin6_flowinfo & IPV6_FLOWINFO_MASK;
8474c9483b2SDavid S. Miller IP6_ECN_flow_init(fl6.flowlabel);
8484c9483b2SDavid S. Miller if (fl6.flowlabel & IPV6_FLOWLABEL_MASK) {
84973c9e02cSGerrit Renker struct ip6_flowlabel *flowlabel;
8504c9483b2SDavid S. Miller flowlabel = fl6_sock_lookup(sk, fl6.flowlabel);
85159c820b2SWillem de Bruijn if (IS_ERR(flowlabel))
85273c9e02cSGerrit Renker return -EINVAL;
85373c9e02cSGerrit Renker fl6_sock_release(flowlabel);
85473c9e02cSGerrit Renker }
85573c9e02cSGerrit Renker }
85673c9e02cSGerrit Renker /*
85773c9e02cSGerrit Renker * connect() to INADDR_ANY means loopback (BSD'ism).
85873c9e02cSGerrit Renker */
85973c9e02cSGerrit Renker if (ipv6_addr_any(&usin->sin6_addr))
86073c9e02cSGerrit Renker usin->sin6_addr.s6_addr[15] = 1;
86173c9e02cSGerrit Renker
86273c9e02cSGerrit Renker addr_type = ipv6_addr_type(&usin->sin6_addr);
86373c9e02cSGerrit Renker
86473c9e02cSGerrit Renker if (addr_type & IPV6_ADDR_MULTICAST)
86573c9e02cSGerrit Renker return -ENETUNREACH;
86673c9e02cSGerrit Renker
86773c9e02cSGerrit Renker if (addr_type & IPV6_ADDR_LINKLOCAL) {
86873c9e02cSGerrit Renker if (addr_len >= sizeof(struct sockaddr_in6) &&
86973c9e02cSGerrit Renker usin->sin6_scope_id) {
87073c9e02cSGerrit Renker /* If interface is set while binding, indices
87173c9e02cSGerrit Renker * must coincide.
87273c9e02cSGerrit Renker */
87373c9e02cSGerrit Renker if (sk->sk_bound_dev_if &&
87473c9e02cSGerrit Renker sk->sk_bound_dev_if != usin->sin6_scope_id)
87573c9e02cSGerrit Renker return -EINVAL;
87673c9e02cSGerrit Renker
87773c9e02cSGerrit Renker sk->sk_bound_dev_if = usin->sin6_scope_id;
87873c9e02cSGerrit Renker }
87973c9e02cSGerrit Renker
88073c9e02cSGerrit Renker /* Connect to link-local address requires an interface */
88173c9e02cSGerrit Renker if (!sk->sk_bound_dev_if)
88273c9e02cSGerrit Renker return -EINVAL;
88373c9e02cSGerrit Renker }
88473c9e02cSGerrit Renker
885efe4208fSEric Dumazet sk->sk_v6_daddr = usin->sin6_addr;
8864c9483b2SDavid S. Miller np->flow_label = fl6.flowlabel;
88773c9e02cSGerrit Renker
88873c9e02cSGerrit Renker /*
88973c9e02cSGerrit Renker * DCCP over IPv4
89073c9e02cSGerrit Renker */
89173c9e02cSGerrit Renker if (addr_type == IPV6_ADDR_MAPPED) {
89273c9e02cSGerrit Renker u32 exthdrlen = icsk->icsk_ext_hdr_len;
89373c9e02cSGerrit Renker struct sockaddr_in sin;
89473c9e02cSGerrit Renker
89573c9e02cSGerrit Renker SOCK_DEBUG(sk, "connect: ipv4 mapped\n");
89673c9e02cSGerrit Renker
89789e9c728SKuniyuki Iwashima if (ipv6_only_sock(sk))
89873c9e02cSGerrit Renker return -ENETUNREACH;
89973c9e02cSGerrit Renker
90073c9e02cSGerrit Renker sin.sin_family = AF_INET;
90173c9e02cSGerrit Renker sin.sin_port = usin->sin6_port;
90273c9e02cSGerrit Renker sin.sin_addr.s_addr = usin->sin6_addr.s6_addr32[3];
90373c9e02cSGerrit Renker
90473c9e02cSGerrit Renker icsk->icsk_af_ops = &dccp_ipv6_mapped;
90573c9e02cSGerrit Renker sk->sk_backlog_rcv = dccp_v4_do_rcv;
90673c9e02cSGerrit Renker
90773c9e02cSGerrit Renker err = dccp_v4_connect(sk, (struct sockaddr *)&sin, sizeof(sin));
90873c9e02cSGerrit Renker if (err) {
90973c9e02cSGerrit Renker icsk->icsk_ext_hdr_len = exthdrlen;
91073c9e02cSGerrit Renker icsk->icsk_af_ops = &dccp_ipv6_af_ops;
91173c9e02cSGerrit Renker sk->sk_backlog_rcv = dccp_v6_do_rcv;
91273c9e02cSGerrit Renker goto failure;
91373c9e02cSGerrit Renker }
914d1e559d0SEric Dumazet np->saddr = sk->sk_v6_rcv_saddr;
91573c9e02cSGerrit Renker return err;
91673c9e02cSGerrit Renker }
91773c9e02cSGerrit Renker
918efe4208fSEric Dumazet if (!ipv6_addr_any(&sk->sk_v6_rcv_saddr))
919efe4208fSEric Dumazet saddr = &sk->sk_v6_rcv_saddr;
92073c9e02cSGerrit Renker
9214c9483b2SDavid S. Miller fl6.flowi6_proto = IPPROTO_DCCP;
922efe4208fSEric Dumazet fl6.daddr = sk->sk_v6_daddr;
9234e3fd7a0SAlexey Dobriyan fl6.saddr = saddr ? *saddr : np->saddr;
9244c9483b2SDavid S. Miller fl6.flowi6_oif = sk->sk_bound_dev_if;
9251958b856SDavid S. Miller fl6.fl6_dport = usin->sin6_port;
9261958b856SDavid S. Miller fl6.fl6_sport = inet->inet_sport;
9273df98d79SPaul Moore security_sk_classify_flow(sk, flowi6_to_flowi_common(&fl6));
92873c9e02cSGerrit Renker
9291e1d04e6SHannes Frederic Sowa opt = rcu_dereference_protected(np->opt, lockdep_sock_is_held(sk));
93045f6fad8SEric Dumazet final_p = fl6_update_dst(&fl6, opt, &final);
93173c9e02cSGerrit Renker
932c4e85f73SSabrina Dubroca dst = ip6_dst_lookup_flow(sock_net(sk), sk, &fl6, final_p);
93368d0c6d3SDavid S. Miller if (IS_ERR(dst)) {
93468d0c6d3SDavid S. Miller err = PTR_ERR(dst);
93573c9e02cSGerrit Renker goto failure;
93614e50e57SDavid S. Miller }
93773c9e02cSGerrit Renker
93873c9e02cSGerrit Renker if (saddr == NULL) {
9394c9483b2SDavid S. Miller saddr = &fl6.saddr;
94028044fc1SJoanne Koong
9418c5dae4cSKuniyuki Iwashima err = inet_bhash2_update_saddr(sk, saddr, AF_INET6);
9428c5dae4cSKuniyuki Iwashima if (err)
94328044fc1SJoanne Koong goto failure;
94428044fc1SJoanne Koong }
94573c9e02cSGerrit Renker
94673c9e02cSGerrit Renker /* set the source address */
9474e3fd7a0SAlexey Dobriyan np->saddr = *saddr;
948c720c7e8SEric Dumazet inet->inet_rcv_saddr = LOOPBACK4_IPV6;
94973c9e02cSGerrit Renker
9506bd4f355SEric Dumazet ip6_dst_store(sk, dst, NULL, NULL);
95173c9e02cSGerrit Renker
95273c9e02cSGerrit Renker icsk->icsk_ext_hdr_len = 0;
95345f6fad8SEric Dumazet if (opt)
95445f6fad8SEric Dumazet icsk->icsk_ext_hdr_len = opt->opt_flen + opt->opt_nflen;
95573c9e02cSGerrit Renker
956c720c7e8SEric Dumazet inet->inet_dport = usin->sin6_port;
95773c9e02cSGerrit Renker
95873c9e02cSGerrit Renker dccp_set_state(sk, DCCP_REQUESTING);
95973c9e02cSGerrit Renker err = inet6_hash_connect(&dccp_death_row, sk);
96073c9e02cSGerrit Renker if (err)
96173c9e02cSGerrit Renker goto late_failure;
962d7f7365fSGerrit Renker
963d7f7365fSGerrit Renker dp->dccps_iss = secure_dccpv6_sequence_number(np->saddr.s6_addr32,
964efe4208fSEric Dumazet sk->sk_v6_daddr.s6_addr32,
965c720c7e8SEric Dumazet inet->inet_sport,
966c720c7e8SEric Dumazet inet->inet_dport);
96773c9e02cSGerrit Renker err = dccp_connect(sk);
96873c9e02cSGerrit Renker if (err)
96973c9e02cSGerrit Renker goto late_failure;
97073c9e02cSGerrit Renker
97173c9e02cSGerrit Renker return 0;
97273c9e02cSGerrit Renker
97373c9e02cSGerrit Renker late_failure:
97473c9e02cSGerrit Renker dccp_set_state(sk, DCCP_CLOSED);
975e0833d1fSKuniyuki Iwashima inet_bhash2_reset_saddr(sk);
97673c9e02cSGerrit Renker __sk_dst_reset(sk);
97773c9e02cSGerrit Renker failure:
978c720c7e8SEric Dumazet inet->inet_dport = 0;
97973c9e02cSGerrit Renker sk->sk_route_caps = 0;
98073c9e02cSGerrit Renker return err;
98173c9e02cSGerrit Renker }
98273c9e02cSGerrit Renker
9833b401a81SStephen Hemminger static const struct inet_connection_sock_af_ops dccp_ipv6_af_ops = {
9843df80d93SArnaldo Carvalho de Melo .queue_xmit = inet6_csk_xmit,
9853df80d93SArnaldo Carvalho de Melo .send_check = dccp_v6_send_check,
9863df80d93SArnaldo Carvalho de Melo .rebuild_header = inet6_sk_rebuild_header,
9873df80d93SArnaldo Carvalho de Melo .conn_request = dccp_v6_conn_request,
9883df80d93SArnaldo Carvalho de Melo .syn_recv_sock = dccp_v6_request_recv_sock,
9893df80d93SArnaldo Carvalho de Melo .net_header_len = sizeof(struct ipv6hdr),
9903df80d93SArnaldo Carvalho de Melo .setsockopt = ipv6_setsockopt,
9913df80d93SArnaldo Carvalho de Melo .getsockopt = ipv6_getsockopt,
992543d9cfeSArnaldo Carvalho de Melo .addr2sockaddr = inet6_csk_addr2sockaddr,
993543d9cfeSArnaldo Carvalho de Melo .sockaddr_len = sizeof(struct sockaddr_in6),
9943df80d93SArnaldo Carvalho de Melo };
9953df80d93SArnaldo Carvalho de Melo
9963df80d93SArnaldo Carvalho de Melo /*
9973df80d93SArnaldo Carvalho de Melo * DCCP over IPv4 via INET6 API
9983df80d93SArnaldo Carvalho de Melo */
9993b401a81SStephen Hemminger static const struct inet_connection_sock_af_ops dccp_ipv6_mapped = {
10003df80d93SArnaldo Carvalho de Melo .queue_xmit = ip_queue_xmit,
10013df80d93SArnaldo Carvalho de Melo .send_check = dccp_v4_send_check,
10023df80d93SArnaldo Carvalho de Melo .rebuild_header = inet_sk_rebuild_header,
10033df80d93SArnaldo Carvalho de Melo .conn_request = dccp_v6_conn_request,
10043df80d93SArnaldo Carvalho de Melo .syn_recv_sock = dccp_v6_request_recv_sock,
10053df80d93SArnaldo Carvalho de Melo .net_header_len = sizeof(struct iphdr),
10063df80d93SArnaldo Carvalho de Melo .setsockopt = ipv6_setsockopt,
10073df80d93SArnaldo Carvalho de Melo .getsockopt = ipv6_getsockopt,
1008543d9cfeSArnaldo Carvalho de Melo .addr2sockaddr = inet6_csk_addr2sockaddr,
1009543d9cfeSArnaldo Carvalho de Melo .sockaddr_len = sizeof(struct sockaddr_in6),
10103df80d93SArnaldo Carvalho de Melo };
10113df80d93SArnaldo Carvalho de Melo
dccp_v6_sk_destruct(struct sock * sk)10121651951eSKuniyuki Iwashima static void dccp_v6_sk_destruct(struct sock *sk)
10131651951eSKuniyuki Iwashima {
10141651951eSKuniyuki Iwashima dccp_destruct_common(sk);
10151651951eSKuniyuki Iwashima inet6_sock_destruct(sk);
10161651951eSKuniyuki Iwashima }
10171651951eSKuniyuki Iwashima
10183df80d93SArnaldo Carvalho de Melo /* NOTE: A lot of things set to zero explicitly by call to
10193df80d93SArnaldo Carvalho de Melo * sk_alloc() so need not be done here.
10203df80d93SArnaldo Carvalho de Melo */
dccp_v6_init_sock(struct sock * sk)10213df80d93SArnaldo Carvalho de Melo static int dccp_v6_init_sock(struct sock *sk)
10223df80d93SArnaldo Carvalho de Melo {
102372478873SArnaldo Carvalho de Melo static __u8 dccp_v6_ctl_sock_initialized;
102472478873SArnaldo Carvalho de Melo int err = dccp_init_sock(sk, dccp_v6_ctl_sock_initialized);
10253df80d93SArnaldo Carvalho de Melo
102672478873SArnaldo Carvalho de Melo if (err == 0) {
102772478873SArnaldo Carvalho de Melo if (unlikely(!dccp_v6_ctl_sock_initialized))
102872478873SArnaldo Carvalho de Melo dccp_v6_ctl_sock_initialized = 1;
10293df80d93SArnaldo Carvalho de Melo inet_csk(sk)->icsk_af_ops = &dccp_ipv6_af_ops;
10301651951eSKuniyuki Iwashima sk->sk_destruct = dccp_v6_sk_destruct;
103172478873SArnaldo Carvalho de Melo }
10323df80d93SArnaldo Carvalho de Melo
10333df80d93SArnaldo Carvalho de Melo return err;
10343df80d93SArnaldo Carvalho de Melo }
10353df80d93SArnaldo Carvalho de Melo
103673c9e02cSGerrit Renker static struct timewait_sock_ops dccp6_timewait_sock_ops = {
103773c9e02cSGerrit Renker .twsk_obj_size = sizeof(struct dccp6_timewait_sock),
103873c9e02cSGerrit Renker };
103973c9e02cSGerrit Renker
10403df80d93SArnaldo Carvalho de Melo static struct proto dccp_v6_prot = {
10413df80d93SArnaldo Carvalho de Melo .name = "DCCPv6",
10423df80d93SArnaldo Carvalho de Melo .owner = THIS_MODULE,
10433df80d93SArnaldo Carvalho de Melo .close = dccp_close,
10443df80d93SArnaldo Carvalho de Melo .connect = dccp_v6_connect,
10453df80d93SArnaldo Carvalho de Melo .disconnect = dccp_disconnect,
10463df80d93SArnaldo Carvalho de Melo .ioctl = dccp_ioctl,
10473df80d93SArnaldo Carvalho de Melo .init = dccp_v6_init_sock,
10483df80d93SArnaldo Carvalho de Melo .setsockopt = dccp_setsockopt,
10493df80d93SArnaldo Carvalho de Melo .getsockopt = dccp_getsockopt,
10503df80d93SArnaldo Carvalho de Melo .sendmsg = dccp_sendmsg,
10513df80d93SArnaldo Carvalho de Melo .recvmsg = dccp_recvmsg,
10523df80d93SArnaldo Carvalho de Melo .backlog_rcv = dccp_v6_do_rcv,
1053496611d7SCraig Gallek .hash = inet6_hash,
1054ab1e0a13SArnaldo Carvalho de Melo .unhash = inet_unhash,
10553df80d93SArnaldo Carvalho de Melo .accept = inet_csk_accept,
1056ab1e0a13SArnaldo Carvalho de Melo .get_port = inet_csk_get_port,
10573df80d93SArnaldo Carvalho de Melo .shutdown = dccp_shutdown,
10581651951eSKuniyuki Iwashima .destroy = dccp_destroy_sock,
10593df80d93SArnaldo Carvalho de Melo .orphan_count = &dccp_orphan_count,
10603df80d93SArnaldo Carvalho de Melo .max_header = MAX_DCCP_HEADER,
10613df80d93SArnaldo Carvalho de Melo .obj_size = sizeof(struct dccp6_sock),
1062f5f80e32SEric Dumazet .ipv6_pinfo_offset = offsetof(struct dccp6_sock, inet6),
10635f0d5a3aSPaul E. McKenney .slab_flags = SLAB_TYPESAFE_BY_RCU,
10643df80d93SArnaldo Carvalho de Melo .rsk_prot = &dccp6_request_sock_ops,
10656d6ee43eSArnaldo Carvalho de Melo .twsk_prot = &dccp6_timewait_sock_ops,
106639d8cda7SPavel Emelyanov .h.hashinfo = &dccp_hashinfo,
10673df80d93SArnaldo Carvalho de Melo };
10683df80d93SArnaldo Carvalho de Melo
106941135cc8SAlexey Dobriyan static const struct inet6_protocol dccp_v6_protocol = {
10703df80d93SArnaldo Carvalho de Melo .handler = dccp_v6_rcv,
10713df80d93SArnaldo Carvalho de Melo .err_handler = dccp_v6_err,
10723df80d93SArnaldo Carvalho de Melo .flags = INET6_PROTO_NOPOLICY | INET6_PROTO_FINAL,
10733df80d93SArnaldo Carvalho de Melo };
10743df80d93SArnaldo Carvalho de Melo
10755708e868SAlexey Dobriyan static const struct proto_ops inet6_dccp_ops = {
10763df80d93SArnaldo Carvalho de Melo .family = PF_INET6,
10773df80d93SArnaldo Carvalho de Melo .owner = THIS_MODULE,
10783df80d93SArnaldo Carvalho de Melo .release = inet6_release,
10793df80d93SArnaldo Carvalho de Melo .bind = inet6_bind,
10803df80d93SArnaldo Carvalho de Melo .connect = inet_stream_connect,
10813df80d93SArnaldo Carvalho de Melo .socketpair = sock_no_socketpair,
10823df80d93SArnaldo Carvalho de Melo .accept = inet_accept,
10833df80d93SArnaldo Carvalho de Melo .getname = inet6_getname,
1084a11e1d43SLinus Torvalds .poll = dccp_poll,
10853df80d93SArnaldo Carvalho de Melo .ioctl = inet6_ioctl,
1086c7cbdbf2SArnd Bergmann .gettstamp = sock_gettstamp,
10873df80d93SArnaldo Carvalho de Melo .listen = inet_dccp_listen,
10883df80d93SArnaldo Carvalho de Melo .shutdown = inet_shutdown,
10893df80d93SArnaldo Carvalho de Melo .setsockopt = sock_common_setsockopt,
10903df80d93SArnaldo Carvalho de Melo .getsockopt = sock_common_getsockopt,
10913df80d93SArnaldo Carvalho de Melo .sendmsg = inet_sendmsg,
10923df80d93SArnaldo Carvalho de Melo .recvmsg = sock_common_recvmsg,
10933df80d93SArnaldo Carvalho de Melo .mmap = sock_no_mmap,
1094543d9cfeSArnaldo Carvalho de Melo #ifdef CONFIG_COMPAT
10953986912fSChristoph Hellwig .compat_ioctl = inet6_compat_ioctl,
1096543d9cfeSArnaldo Carvalho de Melo #endif
10973df80d93SArnaldo Carvalho de Melo };
10983df80d93SArnaldo Carvalho de Melo
10993df80d93SArnaldo Carvalho de Melo static struct inet_protosw dccp_v6_protosw = {
11003df80d93SArnaldo Carvalho de Melo .type = SOCK_DCCP,
11013df80d93SArnaldo Carvalho de Melo .protocol = IPPROTO_DCCP,
11023df80d93SArnaldo Carvalho de Melo .prot = &dccp_v6_prot,
11033df80d93SArnaldo Carvalho de Melo .ops = &inet6_dccp_ops,
1104d83d8461SArnaldo Carvalho de Melo .flags = INET_PROTOSW_ICSK,
11053df80d93SArnaldo Carvalho de Melo };
11063df80d93SArnaldo Carvalho de Melo
dccp_v6_init_net(struct net * net)11072c8c1e72SAlexey Dobriyan static int __net_init dccp_v6_init_net(struct net *net)
11088231bd27SPavel Emelyanov {
1109b98b3304SFlorian Westphal struct dccp_v6_pernet *pn = net_generic(net, dccp_v6_pernet_id);
1110b98b3304SFlorian Westphal
1111d14a0ebdSGerrit Renker if (dccp_hashinfo.bhash == NULL)
1112d14a0ebdSGerrit Renker return -ESOCKTNOSUPPORT;
1113334527d3SPavel Emelyanov
1114b98b3304SFlorian Westphal return inet_ctl_sock_create(&pn->v6_ctl_sk, PF_INET6,
1115334527d3SPavel Emelyanov SOCK_DCCP, IPPROTO_DCCP, net);
11168231bd27SPavel Emelyanov }
11178231bd27SPavel Emelyanov
dccp_v6_exit_net(struct net * net)11182c8c1e72SAlexey Dobriyan static void __net_exit dccp_v6_exit_net(struct net *net)
11198231bd27SPavel Emelyanov {
1120b98b3304SFlorian Westphal struct dccp_v6_pernet *pn = net_generic(net, dccp_v6_pernet_id);
1121b98b3304SFlorian Westphal
1122b98b3304SFlorian Westphal inet_ctl_sock_destroy(pn->v6_ctl_sk);
11238231bd27SPavel Emelyanov }
11248231bd27SPavel Emelyanov
11258231bd27SPavel Emelyanov static struct pernet_operations dccp_v6_ops = {
11268231bd27SPavel Emelyanov .init = dccp_v6_init_net,
11278231bd27SPavel Emelyanov .exit = dccp_v6_exit_net,
1128b98b3304SFlorian Westphal .id = &dccp_v6_pernet_id,
1129b98b3304SFlorian Westphal .size = sizeof(struct dccp_v6_pernet),
11308231bd27SPavel Emelyanov };
11318231bd27SPavel Emelyanov
dccp_v6_init(void)11323df80d93SArnaldo Carvalho de Melo static int __init dccp_v6_init(void)
11333df80d93SArnaldo Carvalho de Melo {
11343df80d93SArnaldo Carvalho de Melo int err = proto_register(&dccp_v6_prot, 1);
11353df80d93SArnaldo Carvalho de Melo
1136a0f9a4c2SXin Long if (err)
11373df80d93SArnaldo Carvalho de Melo goto out;
11383df80d93SArnaldo Carvalho de Melo
11393df80d93SArnaldo Carvalho de Melo inet6_register_protosw(&dccp_v6_protosw);
114072478873SArnaldo Carvalho de Melo
11418231bd27SPavel Emelyanov err = register_pernet_subsys(&dccp_v6_ops);
1142a0f9a4c2SXin Long if (err)
11438231bd27SPavel Emelyanov goto out_destroy_ctl_sock;
1144a0f9a4c2SXin Long
1145a0f9a4c2SXin Long err = inet6_add_protocol(&dccp_v6_protocol, IPPROTO_DCCP);
1146a0f9a4c2SXin Long if (err)
1147a0f9a4c2SXin Long goto out_unregister_proto;
1148a0f9a4c2SXin Long
11493df80d93SArnaldo Carvalho de Melo out:
11503df80d93SArnaldo Carvalho de Melo return err;
11513df80d93SArnaldo Carvalho de Melo out_unregister_proto:
1152a0f9a4c2SXin Long unregister_pernet_subsys(&dccp_v6_ops);
1153a0f9a4c2SXin Long out_destroy_ctl_sock:
1154a0f9a4c2SXin Long inet6_unregister_protosw(&dccp_v6_protosw);
11553df80d93SArnaldo Carvalho de Melo proto_unregister(&dccp_v6_prot);
11563df80d93SArnaldo Carvalho de Melo goto out;
11573df80d93SArnaldo Carvalho de Melo }
11583df80d93SArnaldo Carvalho de Melo
dccp_v6_exit(void)11593df80d93SArnaldo Carvalho de Melo static void __exit dccp_v6_exit(void)
11603df80d93SArnaldo Carvalho de Melo {
11613df80d93SArnaldo Carvalho de Melo inet6_del_protocol(&dccp_v6_protocol, IPPROTO_DCCP);
1162a0f9a4c2SXin Long unregister_pernet_subsys(&dccp_v6_ops);
11633df80d93SArnaldo Carvalho de Melo inet6_unregister_protosw(&dccp_v6_protosw);
11643df80d93SArnaldo Carvalho de Melo proto_unregister(&dccp_v6_prot);
11653df80d93SArnaldo Carvalho de Melo }
11663df80d93SArnaldo Carvalho de Melo
11673df80d93SArnaldo Carvalho de Melo module_init(dccp_v6_init);
11683df80d93SArnaldo Carvalho de Melo module_exit(dccp_v6_exit);
11693df80d93SArnaldo Carvalho de Melo
11703df80d93SArnaldo Carvalho de Melo /*
11713df80d93SArnaldo Carvalho de Melo * __stringify doesn't likes enums, so use SOCK_DCCP (6) and IPPROTO_DCCP (33)
11723df80d93SArnaldo Carvalho de Melo * values directly, Also cover the case where the protocol is not specified,
11733df80d93SArnaldo Carvalho de Melo * i.e. net-pf-PF_INET6-proto-0-type-SOCK_DCCP
11743df80d93SArnaldo Carvalho de Melo */
11757131c6c7SJean Delvare MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_INET6, 33, 6);
11767131c6c7SJean Delvare MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_INET6, 0, 6);
11773df80d93SArnaldo Carvalho de Melo MODULE_LICENSE("GPL");
11783df80d93SArnaldo Carvalho de Melo MODULE_AUTHOR("Arnaldo Carvalho de Melo <acme@mandriva.com>");
11793df80d93SArnaldo Carvalho de Melo MODULE_DESCRIPTION("DCCPv6 - Datagram Congestion Controlled Protocol");
1180