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> 326be49deaSJason Xing #include <net/rstreason.h> 333df80d93SArnaldo Carvalho de Melo 343df80d93SArnaldo Carvalho de Melo #include "dccp.h" 353df80d93SArnaldo Carvalho de Melo #include "ipv6.h" 364b79f0afSIan McDonald #include "feat.h" 373df80d93SArnaldo Carvalho de Melo 38b98b3304SFlorian Westphal struct dccp_v6_pernet { 39b98b3304SFlorian Westphal struct sock *v6_ctl_sk; 40b98b3304SFlorian Westphal }; 41b98b3304SFlorian Westphal 42b98b3304SFlorian Westphal static unsigned int dccp_v6_pernet_id __read_mostly; 43b98b3304SFlorian Westphal 44b98b3304SFlorian Westphal /* The per-net v6_ctl_sk is used for sending RSTs and ACKs */ 4572478873SArnaldo Carvalho de Melo 463b401a81SStephen Hemminger static const struct inet_connection_sock_af_ops dccp_ipv6_mapped; 473b401a81SStephen Hemminger static const struct inet_connection_sock_af_ops dccp_ipv6_af_ops; 483df80d93SArnaldo Carvalho de Melo 496f4e5fffSGerrit Renker /* add pseudo-header to DCCP checksum stored in skb->csum */ 50868c86bcSAl Viro static inline __sum16 dccp_v6_csum_finish(struct sk_buff *skb, 51b71d1d42SEric Dumazet const struct in6_addr *saddr, 52b71d1d42SEric Dumazet const struct in6_addr *daddr) 533df80d93SArnaldo Carvalho de Melo { 546f4e5fffSGerrit Renker return csum_ipv6_magic(saddr, daddr, skb->len, IPPROTO_DCCP, skb->csum); 556f4e5fffSGerrit Renker } 566f4e5fffSGerrit Renker 57bb296246SHerbert Xu static inline void dccp_v6_send_check(struct sock *sk, struct sk_buff *skb) 586f4e5fffSGerrit Renker { 596f4e5fffSGerrit Renker struct ipv6_pinfo *np = inet6_sk(sk); 606f4e5fffSGerrit Renker struct dccp_hdr *dh = dccp_hdr(skb); 616f4e5fffSGerrit Renker 626f4e5fffSGerrit Renker dccp_csum_outgoing(skb); 63efe4208fSEric Dumazet dh->dccph_checksum = dccp_v6_csum_finish(skb, &np->saddr, &sk->sk_v6_daddr); 643df80d93SArnaldo Carvalho de Melo } 653df80d93SArnaldo Carvalho de Melo 666e5714eaSDavid S. Miller static inline __u64 dccp_v6_init_sequence(struct sk_buff *skb) 67d7f7365fSGerrit Renker { 680660e03fSArnaldo Carvalho de Melo return secure_dccpv6_sequence_number(ipv6_hdr(skb)->daddr.s6_addr32, 690660e03fSArnaldo Carvalho de Melo ipv6_hdr(skb)->saddr.s6_addr32, 70865e9022SGerrit Renker dccp_hdr(skb)->dccph_dport, 71865e9022SGerrit Renker dccp_hdr(skb)->dccph_sport ); 72d7f7365fSGerrit Renker 733df80d93SArnaldo Carvalho de Melo } 743df80d93SArnaldo Carvalho de Melo 7532bbd879SStefano Brivio static int dccp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, 76d5fdd6baSBrian Haley u8 type, u8 code, int offset, __be32 info) 773df80d93SArnaldo Carvalho de Melo { 78977ad86cSJann Horn const struct ipv6hdr *hdr; 791aa9d1a0SEric Dumazet const struct dccp_hdr *dh; 80e0bcfb0cSWei Yongjun struct dccp_sock *dp; 813df80d93SArnaldo Carvalho de Melo struct ipv6_pinfo *np; 823df80d93SArnaldo Carvalho de Melo struct sock *sk; 833df80d93SArnaldo Carvalho de Melo int err; 843df80d93SArnaldo Carvalho de Melo __u64 seq; 85ca12a1a4SPavel Emelyanov struct net *net = dev_net(skb->dev); 863df80d93SArnaldo Carvalho de Melo 876af28974SEric Dumazet if (!pskb_may_pull(skb, offset + sizeof(*dh))) 886af28974SEric Dumazet return -EINVAL; 89977ad86cSJann Horn dh = (struct dccp_hdr *)(skb->data + offset); 90977ad86cSJann Horn if (!pskb_may_pull(skb, offset + __dccp_basic_hdr_len(dh))) 91977ad86cSJann Horn return -EINVAL; 92977ad86cSJann Horn hdr = (const struct ipv6hdr *)skb->data; 931aa9d1a0SEric Dumazet dh = (struct dccp_hdr *)(skb->data + offset); 94860239c5SWei Yongjun 9552036a43SEric Dumazet sk = __inet6_lookup_established(net, &dccp_hashinfo, 96671a1c74SPavel Emelyanov &hdr->daddr, dh->dccph_dport, 9752036a43SEric Dumazet &hdr->saddr, ntohs(dh->dccph_sport), 984297a0efSDavid Ahern inet6_iif(skb), 0); 993df80d93SArnaldo Carvalho de Melo 10052036a43SEric Dumazet if (!sk) { 101a16292a0SEric Dumazet __ICMP6_INC_STATS(net, __in6_dev_get(skb->dev), 102e41b5368SDenis V. Lunev ICMP6_MIB_INERRORS); 10332bbd879SStefano Brivio return -ENOENT; 1043df80d93SArnaldo Carvalho de Melo } 1053df80d93SArnaldo Carvalho de Melo 1063df80d93SArnaldo Carvalho de Melo if (sk->sk_state == DCCP_TIME_WAIT) { 1079469c7b4SYOSHIFUJI Hideaki inet_twsk_put(inet_twsk(sk)); 10832bbd879SStefano Brivio return 0; 1093df80d93SArnaldo Carvalho de Melo } 11052036a43SEric Dumazet seq = dccp_hdr_seq(dh); 11132bbd879SStefano Brivio if (sk->sk_state == DCCP_NEW_SYN_RECV) { 11232bbd879SStefano Brivio dccp_req_err(sk, seq); 11332bbd879SStefano Brivio return 0; 11432bbd879SStefano Brivio } 1153df80d93SArnaldo Carvalho de Melo 1163df80d93SArnaldo Carvalho de Melo bh_lock_sock(sk); 1173df80d93SArnaldo Carvalho de Melo if (sock_owned_by_user(sk)) 11802a1d6e7SEric Dumazet __NET_INC_STATS(net, LINUX_MIB_LOCKDROPPEDICMPS); 1193df80d93SArnaldo Carvalho de Melo 1203df80d93SArnaldo Carvalho de Melo if (sk->sk_state == DCCP_CLOSED) 1213df80d93SArnaldo Carvalho de Melo goto out; 1223df80d93SArnaldo Carvalho de Melo 123e0bcfb0cSWei Yongjun dp = dccp_sk(sk); 124e0bcfb0cSWei Yongjun if ((1 << sk->sk_state) & ~(DCCPF_REQUESTING | DCCPF_LISTEN) && 125e0bcfb0cSWei Yongjun !between48(seq, dp->dccps_awl, dp->dccps_awh)) { 12602a1d6e7SEric Dumazet __NET_INC_STATS(net, LINUX_MIB_OUTOFWINDOWICMPS); 127e0bcfb0cSWei Yongjun goto out; 128e0bcfb0cSWei Yongjun } 129e0bcfb0cSWei Yongjun 1303df80d93SArnaldo Carvalho de Melo np = inet6_sk(sk); 1313df80d93SArnaldo Carvalho de Melo 132ec18d9a2SDavid S. Miller if (type == NDISC_REDIRECT) { 13345caeaa5SJon Maxwell if (!sock_owned_by_user(sk)) { 134ec18d9a2SDavid S. Miller struct dst_entry *dst = __sk_dst_check(sk, np->dst_cookie); 135ec18d9a2SDavid S. Miller 1361ed5c48fSDavid S. Miller if (dst) 1376700c270SDavid S. Miller dst->ops->redirect(dst, sk, skb); 13845caeaa5SJon Maxwell } 139bd784a14SDuan Jiong goto out; 140ec18d9a2SDavid S. Miller } 141ec18d9a2SDavid S. Miller 1423df80d93SArnaldo Carvalho de Melo if (type == ICMPV6_PKT_TOOBIG) { 1433df80d93SArnaldo Carvalho de Melo struct dst_entry *dst = NULL; 1443df80d93SArnaldo Carvalho de Melo 14593b36cf3SHannes Frederic Sowa if (!ip6_sk_accept_pmtu(sk)) 14693b36cf3SHannes Frederic Sowa goto out; 14793b36cf3SHannes Frederic Sowa 1483df80d93SArnaldo Carvalho de Melo if (sock_owned_by_user(sk)) 1493df80d93SArnaldo Carvalho de Melo goto out; 1503df80d93SArnaldo Carvalho de Melo if ((1 << sk->sk_state) & (DCCPF_LISTEN | DCCPF_CLOSED)) 1513df80d93SArnaldo Carvalho de Melo goto out; 1523df80d93SArnaldo Carvalho de Melo 15335ad9b9cSDavid S. Miller dst = inet6_csk_update_pmtu(sk, ntohl(info)); 15435ad9b9cSDavid S. Miller if (!dst) 1553df80d93SArnaldo Carvalho de Melo goto out; 1563df80d93SArnaldo Carvalho de Melo 15735ad9b9cSDavid S. Miller if (inet_csk(sk)->icsk_pmtu_cookie > dst_mtu(dst)) 1583df80d93SArnaldo Carvalho de Melo dccp_sync_mss(sk, dst_mtu(dst)); 1593df80d93SArnaldo Carvalho de Melo goto out; 1603df80d93SArnaldo Carvalho de Melo } 1613df80d93SArnaldo Carvalho de Melo 1623df80d93SArnaldo Carvalho de Melo icmpv6_err_convert(type, code, &err); 1633df80d93SArnaldo Carvalho de Melo 1643df80d93SArnaldo Carvalho de Melo /* Might be for an request_sock */ 1653df80d93SArnaldo Carvalho de Melo switch (sk->sk_state) { 1663df80d93SArnaldo Carvalho de Melo case DCCP_REQUESTING: 1673df80d93SArnaldo Carvalho de Melo case DCCP_RESPOND: /* Cannot happen. 1683df80d93SArnaldo Carvalho de Melo It can, it SYNs are crossed. --ANK */ 1693df80d93SArnaldo Carvalho de Melo if (!sock_owned_by_user(sk)) { 170aa62d76bSEric Dumazet __DCCP_INC_STATS(DCCP_MIB_ATTEMPTFAILS); 1713df80d93SArnaldo Carvalho de Melo sk->sk_err = err; 1723df80d93SArnaldo Carvalho de Melo /* 1733df80d93SArnaldo Carvalho de Melo * Wake people up to see the error 1743df80d93SArnaldo Carvalho de Melo * (see connect in sock.c) 1753df80d93SArnaldo Carvalho de Melo */ 176e3ae2365SAlexander Aring sk_error_report(sk); 1773df80d93SArnaldo Carvalho de Melo dccp_done(sk); 1789a25f0cbSEric Dumazet } else { 1799a25f0cbSEric Dumazet WRITE_ONCE(sk->sk_err_soft, err); 1809a25f0cbSEric Dumazet } 1813df80d93SArnaldo Carvalho de Melo goto out; 1823df80d93SArnaldo Carvalho de Melo } 1833df80d93SArnaldo Carvalho de Melo 1843fa29971SEric Dumazet if (!sock_owned_by_user(sk) && inet6_test_bit(RECVERR6, sk)) { 1853df80d93SArnaldo Carvalho de Melo sk->sk_err = err; 186e3ae2365SAlexander Aring sk_error_report(sk); 1879a25f0cbSEric Dumazet } else { 1889a25f0cbSEric Dumazet WRITE_ONCE(sk->sk_err_soft, err); 1899a25f0cbSEric Dumazet } 1903df80d93SArnaldo Carvalho de Melo out: 1913df80d93SArnaldo Carvalho de Melo bh_unlock_sock(sk); 1923df80d93SArnaldo Carvalho de Melo sock_put(sk); 19332bbd879SStefano Brivio return 0; 1943df80d93SArnaldo Carvalho de Melo } 1953df80d93SArnaldo Carvalho de Melo 1963df80d93SArnaldo Carvalho de Melo 197ea3bea3aSEric Dumazet static int dccp_v6_send_response(const struct sock *sk, struct request_sock *req) 1983df80d93SArnaldo Carvalho de Melo { 199634fb979SEric Dumazet struct inet_request_sock *ireq = inet_rsk(req); 2003df80d93SArnaldo Carvalho de Melo struct ipv6_pinfo *np = inet6_sk(sk); 2013df80d93SArnaldo Carvalho de Melo struct sk_buff *skb; 20220c59de2SArnaud Ebalard struct in6_addr *final_p, final; 2034c9483b2SDavid S. Miller struct flowi6 fl6; 2043df80d93SArnaldo Carvalho de Melo int err = -1; 205fd80eb94SDenis V. Lunev struct dst_entry *dst; 2063df80d93SArnaldo Carvalho de Melo 2074c9483b2SDavid S. Miller memset(&fl6, 0, sizeof(fl6)); 2084c9483b2SDavid S. Miller fl6.flowi6_proto = IPPROTO_DCCP; 209634fb979SEric Dumazet fl6.daddr = ireq->ir_v6_rmt_addr; 210634fb979SEric Dumazet fl6.saddr = ireq->ir_v6_loc_addr; 2114c9483b2SDavid S. Miller fl6.flowlabel = 0; 212634fb979SEric Dumazet fl6.flowi6_oif = ireq->ir_iif; 213634fb979SEric Dumazet fl6.fl6_dport = ireq->ir_rmt_port; 214b44084c2SEric Dumazet fl6.fl6_sport = htons(ireq->ir_num); 2153df98d79SPaul Moore security_req_classify_flow(req, flowi6_to_flowi_common(&fl6)); 2163df80d93SArnaldo Carvalho de Melo 2173df80d93SArnaldo Carvalho de Melo 21845f6fad8SEric Dumazet rcu_read_lock(); 21945f6fad8SEric Dumazet final_p = fl6_update_dst(&fl6, rcu_dereference(np->opt), &final); 22045f6fad8SEric Dumazet rcu_read_unlock(); 2213df80d93SArnaldo Carvalho de Melo 222c4e85f73SSabrina Dubroca dst = ip6_dst_lookup_flow(sock_net(sk), sk, &fl6, final_p); 22368d0c6d3SDavid S. Miller if (IS_ERR(dst)) { 22468d0c6d3SDavid S. Miller err = PTR_ERR(dst); 22568d0c6d3SDavid S. Miller dst = NULL; 2263df80d93SArnaldo Carvalho de Melo goto done; 22768d0c6d3SDavid S. Miller } 2283df80d93SArnaldo Carvalho de Melo 2293df80d93SArnaldo Carvalho de Melo skb = dccp_make_response(sk, dst, req); 2303df80d93SArnaldo Carvalho de Melo if (skb != NULL) { 2313df80d93SArnaldo Carvalho de Melo struct dccp_hdr *dh = dccp_hdr(skb); 23256ac42bcSHuw Davies struct ipv6_txoptions *opt; 23345329e71SArnaldo Carvalho de Melo 2346f4e5fffSGerrit Renker dh->dccph_checksum = dccp_v6_csum_finish(skb, 235634fb979SEric Dumazet &ireq->ir_v6_loc_addr, 236634fb979SEric Dumazet &ireq->ir_v6_rmt_addr); 237634fb979SEric Dumazet fl6.daddr = ireq->ir_v6_rmt_addr; 23845f6fad8SEric Dumazet rcu_read_lock(); 23956ac42bcSHuw Davies opt = ireq->ipv6_opt; 24056ac42bcSHuw Davies if (!opt) 24156ac42bcSHuw Davies opt = rcu_dereference(np->opt); 2423c5b4d69SEric Dumazet err = ip6_xmit(sk, skb, &fl6, READ_ONCE(sk->sk_mark), opt, 24310bbf165SEric Dumazet np->tclass, READ_ONCE(sk->sk_priority)); 24445f6fad8SEric Dumazet rcu_read_unlock(); 245b9df3cb8SGerrit Renker err = net_xmit_eval(err); 2463df80d93SArnaldo Carvalho de Melo } 2473df80d93SArnaldo Carvalho de Melo 2483df80d93SArnaldo Carvalho de Melo done: 2490cbd7825SDavid S. Miller dst_release(dst); 2503df80d93SArnaldo Carvalho de Melo return err; 2513df80d93SArnaldo Carvalho de Melo } 2523df80d93SArnaldo Carvalho de Melo 2533df80d93SArnaldo Carvalho de Melo static void dccp_v6_reqsk_destructor(struct request_sock *req) 2543df80d93SArnaldo Carvalho de Melo { 255d99a7bd2SGerrit Renker dccp_feat_list_purge(&dccp_rsk(req)->dreq_featneg); 25656ac42bcSHuw Davies kfree(inet_rsk(req)->ipv6_opt); 257634fb979SEric Dumazet kfree_skb(inet_rsk(req)->pktopts); 2583df80d93SArnaldo Carvalho de Melo } 2593df80d93SArnaldo Carvalho de Melo 2606be49deaSJason Xing static void dccp_v6_ctl_send_reset(const struct sock *sk, struct sk_buff *rxskb, 2616be49deaSJason Xing enum sk_rst_reason reason) 2623df80d93SArnaldo Carvalho de Melo { 263b71d1d42SEric Dumazet const struct ipv6hdr *rxip6h; 2643df80d93SArnaldo Carvalho de Melo struct sk_buff *skb; 2654c9483b2SDavid S. Miller struct flowi6 fl6; 266adf30907SEric Dumazet struct net *net = dev_net(skb_dst(rxskb)->dev); 267b98b3304SFlorian Westphal struct dccp_v6_pernet *pn; 268b98b3304SFlorian Westphal struct sock *ctl_sk; 269adf30907SEric Dumazet struct dst_entry *dst; 2703df80d93SArnaldo Carvalho de Melo 271e356d37aSGerrit Renker if (dccp_hdr(rxskb)->dccph_type == DCCP_PKT_RESET) 2723df80d93SArnaldo Carvalho de Melo return; 2733df80d93SArnaldo Carvalho de Melo 2743df80d93SArnaldo Carvalho de Melo if (!ipv6_unicast_destination(rxskb)) 2753df80d93SArnaldo Carvalho de Melo return; 2763df80d93SArnaldo Carvalho de Melo 277b98b3304SFlorian Westphal pn = net_generic(net, dccp_v6_pernet_id); 278b98b3304SFlorian Westphal ctl_sk = pn->v6_ctl_sk; 27902047741SPavel Emelyanov skb = dccp_ctl_make_reset(ctl_sk, rxskb); 2803df80d93SArnaldo Carvalho de Melo if (skb == NULL) 2813df80d93SArnaldo Carvalho de Melo return; 2823df80d93SArnaldo Carvalho de Melo 2830660e03fSArnaldo Carvalho de Melo rxip6h = ipv6_hdr(rxskb); 284e356d37aSGerrit Renker dccp_hdr(skb)->dccph_checksum = dccp_v6_csum_finish(skb, &rxip6h->saddr, 2850660e03fSArnaldo Carvalho de Melo &rxip6h->daddr); 2866f4e5fffSGerrit Renker 2874c9483b2SDavid S. Miller memset(&fl6, 0, sizeof(fl6)); 2884e3fd7a0SAlexey Dobriyan fl6.daddr = rxip6h->saddr; 2894e3fd7a0SAlexey Dobriyan fl6.saddr = rxip6h->daddr; 2906f4e5fffSGerrit Renker 2914c9483b2SDavid S. Miller fl6.flowi6_proto = IPPROTO_DCCP; 2924c9483b2SDavid S. Miller fl6.flowi6_oif = inet6_iif(rxskb); 2931958b856SDavid S. Miller fl6.fl6_dport = dccp_hdr(skb)->dccph_dport; 2941958b856SDavid S. Miller fl6.fl6_sport = dccp_hdr(skb)->dccph_sport; 2953df98d79SPaul Moore security_skb_classify_flow(rxskb, flowi6_to_flowi_common(&fl6)); 2963df80d93SArnaldo Carvalho de Melo 2973df80d93SArnaldo Carvalho de Melo /* sk = NULL, but it is safe for now. RST socket required. */ 298c4e85f73SSabrina Dubroca dst = ip6_dst_lookup_flow(sock_net(ctl_sk), ctl_sk, &fl6, NULL); 29968d0c6d3SDavid S. Miller if (!IS_ERR(dst)) { 300adf30907SEric Dumazet skb_dst_set(skb, dst); 3014f6570d7SEric Dumazet ip6_xmit(ctl_sk, skb, &fl6, 0, NULL, 0, 0); 3027309f882SEric Dumazet DCCP_INC_STATS(DCCP_MIB_OUTSEGS); 3037309f882SEric Dumazet DCCP_INC_STATS(DCCP_MIB_OUTRSTS); 3043df80d93SArnaldo Carvalho de Melo return; 3053df80d93SArnaldo Carvalho de Melo } 3063df80d93SArnaldo Carvalho de Melo 3073df80d93SArnaldo Carvalho de Melo kfree_skb(skb); 3083df80d93SArnaldo Carvalho de Melo } 3093df80d93SArnaldo Carvalho de Melo 31073c9e02cSGerrit Renker static struct request_sock_ops dccp6_request_sock_ops = { 31173c9e02cSGerrit Renker .family = AF_INET6, 31273c9e02cSGerrit Renker .obj_size = sizeof(struct dccp6_request_sock), 31373c9e02cSGerrit Renker .rtx_syn_ack = dccp_v6_send_response, 31473c9e02cSGerrit Renker .send_ack = dccp_reqsk_send_ack, 31573c9e02cSGerrit Renker .destructor = dccp_v6_reqsk_destructor, 31673c9e02cSGerrit Renker .send_reset = dccp_v6_ctl_send_reset, 317c72e1183SEric Dumazet .syn_ack_timeout = dccp_syn_ack_timeout, 31873c9e02cSGerrit Renker }; 31973c9e02cSGerrit Renker 3203df80d93SArnaldo Carvalho de Melo static int dccp_v6_conn_request(struct sock *sk, struct sk_buff *skb) 3213df80d93SArnaldo Carvalho de Melo { 3223df80d93SArnaldo Carvalho de Melo struct request_sock *req; 3233df80d93SArnaldo Carvalho de Melo struct dccp_request_sock *dreq; 324634fb979SEric Dumazet struct inet_request_sock *ireq; 3253df80d93SArnaldo Carvalho de Melo struct ipv6_pinfo *np = inet6_sk(sk); 32660fe62e7SAndrea Bittau const __be32 service = dccp_hdr_request(skb)->dccph_req_service; 3273df80d93SArnaldo Carvalho de Melo struct dccp_skb_cb *dcb = DCCP_SKB_CB(skb); 3283df80d93SArnaldo Carvalho de Melo 3293df80d93SArnaldo Carvalho de Melo if (skb->protocol == htons(ETH_P_IP)) 3303df80d93SArnaldo Carvalho de Melo return dccp_v4_conn_request(sk, skb); 3313df80d93SArnaldo Carvalho de Melo 3323df80d93SArnaldo Carvalho de Melo if (!ipv6_unicast_destination(skb)) 3334a5409a5SGerrit Renker return 0; /* discard, don't send a reset here */ 3343df80d93SArnaldo Carvalho de Melo 335dcc32f4fSJakub Kicinski if (ipv6_addr_v4mapped(&ipv6_hdr(skb)->saddr)) { 336dcc32f4fSJakub Kicinski __IP6_INC_STATS(sock_net(sk), NULL, IPSTATS_MIB_INHDRERRORS); 337dcc32f4fSJakub Kicinski return 0; 338dcc32f4fSJakub Kicinski } 339dcc32f4fSJakub Kicinski 3403df80d93SArnaldo Carvalho de Melo if (dccp_bad_service_code(sk, service)) { 3414a5409a5SGerrit Renker dcb->dccpd_reset_code = DCCP_RESET_CODE_BAD_SERVICE_CODE; 3423df80d93SArnaldo Carvalho de Melo goto drop; 3433df80d93SArnaldo Carvalho de Melo } 3443df80d93SArnaldo Carvalho de Melo /* 3453df80d93SArnaldo Carvalho de Melo * There are no SYN attacks on IPv6, yet... 3463df80d93SArnaldo Carvalho de Melo */ 3474a5409a5SGerrit Renker dcb->dccpd_reset_code = DCCP_RESET_CODE_TOO_BUSY; 3483df80d93SArnaldo Carvalho de Melo if (inet_csk_reqsk_queue_is_full(sk)) 3493df80d93SArnaldo Carvalho de Melo goto drop; 3503df80d93SArnaldo Carvalho de Melo 3515ea8ea2cSEric Dumazet if (sk_acceptq_is_full(sk)) 3523df80d93SArnaldo Carvalho de Melo goto drop; 3533df80d93SArnaldo Carvalho de Melo 354a1a5344dSEric Dumazet req = inet_reqsk_alloc(&dccp6_request_sock_ops, sk, true); 3553df80d93SArnaldo Carvalho de Melo if (req == NULL) 3563df80d93SArnaldo Carvalho de Melo goto drop; 3573df80d93SArnaldo Carvalho de Melo 358ac75773cSGerrit Renker if (dccp_reqsk_init(req, dccp_sk(sk), skb)) 359ac75773cSGerrit Renker goto drop_and_free; 3603df80d93SArnaldo Carvalho de Melo 3618b819412SGerrit Renker dreq = dccp_rsk(req); 3628b819412SGerrit Renker if (dccp_parse_options(sk, dreq, skb)) 3638b819412SGerrit Renker goto drop_and_free; 3648b819412SGerrit Renker 365634fb979SEric Dumazet ireq = inet_rsk(req); 366634fb979SEric Dumazet ireq->ir_v6_rmt_addr = ipv6_hdr(skb)->saddr; 367634fb979SEric Dumazet ireq->ir_v6_loc_addr = ipv6_hdr(skb)->daddr; 3683f66b083SEric Dumazet ireq->ireq_family = AF_INET6; 369b855ff82SEric Dumazet ireq->ir_mark = inet_request_mark(sk, skb); 3703df80d93SArnaldo Carvalho de Melo 37123be1e0eSKuniyuki Iwashima if (security_inet_conn_request(sk, skb, req)) 37223be1e0eSKuniyuki Iwashima goto drop_and_free; 37323be1e0eSKuniyuki Iwashima 374a224772dSEric Dumazet if (ipv6_opt_accepted(sk, skb, IP6CB(skb)) || 3753df80d93SArnaldo Carvalho de Melo np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo || 3763df80d93SArnaldo Carvalho de Melo np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim) { 37763354797SReshetova, Elena refcount_inc(&skb->users); 378634fb979SEric Dumazet ireq->pktopts = skb; 3793df80d93SArnaldo Carvalho de Melo } 38036f7cec4SEric Dumazet ireq->ir_iif = READ_ONCE(sk->sk_bound_dev_if); 3813df80d93SArnaldo Carvalho de Melo 3823df80d93SArnaldo Carvalho de Melo /* So that link locals have meaning */ 38336f7cec4SEric Dumazet if (!ireq->ir_iif && 384634fb979SEric Dumazet ipv6_addr_type(&ireq->ir_v6_rmt_addr) & IPV6_ADDR_LINKLOCAL) 385634fb979SEric Dumazet ireq->ir_iif = inet6_iif(skb); 3863df80d93SArnaldo Carvalho de Melo 3873df80d93SArnaldo Carvalho de Melo /* 3883df80d93SArnaldo Carvalho de Melo * Step 3: Process LISTEN state 3893df80d93SArnaldo Carvalho de Melo * 3903df80d93SArnaldo Carvalho de Melo * Set S.ISR, S.GSR, S.SWL, S.SWH from packet or Init Cookie 3913df80d93SArnaldo Carvalho de Melo * 392f541fb7eSSamuel Jero * Setting S.SWL/S.SWH to is deferred to dccp_create_openreq_child(). 3933df80d93SArnaldo Carvalho de Melo */ 3943df80d93SArnaldo Carvalho de Melo dreq->dreq_isr = dcb->dccpd_seq; 395f541fb7eSSamuel Jero dreq->dreq_gsr = dreq->dreq_isr; 396865e9022SGerrit Renker dreq->dreq_iss = dccp_v6_init_sequence(skb); 397f541fb7eSSamuel Jero dreq->dreq_gss = dreq->dreq_iss; 3983df80d93SArnaldo Carvalho de Melo dreq->dreq_service = service; 3993df80d93SArnaldo Carvalho de Melo 4001a2c6181SChristoph Paasch if (dccp_v6_send_response(sk, req)) 4013df80d93SArnaldo Carvalho de Melo goto drop_and_free; 4023df80d93SArnaldo Carvalho de Melo 403*ff46e3b4Sluoxuanqiang if (unlikely(!inet_csk_reqsk_queue_hash_add(sk, req, DCCP_TIMEOUT_INIT))) 404*ff46e3b4Sluoxuanqiang reqsk_free(req); 405*ff46e3b4Sluoxuanqiang else 4060c2232b0SXin Long reqsk_put(req); 407*ff46e3b4Sluoxuanqiang 4083df80d93SArnaldo Carvalho de Melo return 0; 4093df80d93SArnaldo Carvalho de Melo 4103df80d93SArnaldo Carvalho de Melo drop_and_free: 4113df80d93SArnaldo Carvalho de Melo reqsk_free(req); 4123df80d93SArnaldo Carvalho de Melo drop: 413aa62d76bSEric Dumazet __DCCP_INC_STATS(DCCP_MIB_ATTEMPTFAILS); 4143df80d93SArnaldo Carvalho de Melo return -1; 4153df80d93SArnaldo Carvalho de Melo } 4163df80d93SArnaldo Carvalho de Melo 4170c27171eSEric Dumazet static struct sock *dccp_v6_request_recv_sock(const struct sock *sk, 4183df80d93SArnaldo Carvalho de Melo struct sk_buff *skb, 4193df80d93SArnaldo Carvalho de Melo struct request_sock *req, 4205e0724d0SEric Dumazet struct dst_entry *dst, 4215e0724d0SEric Dumazet struct request_sock *req_unhash, 4225e0724d0SEric Dumazet bool *own_req) 4233df80d93SArnaldo Carvalho de Melo { 424634fb979SEric Dumazet struct inet_request_sock *ireq = inet_rsk(req); 4250c27171eSEric Dumazet struct ipv6_pinfo *newnp; 4260c27171eSEric Dumazet const struct ipv6_pinfo *np = inet6_sk(sk); 42745f6fad8SEric Dumazet struct ipv6_txoptions *opt; 4283df80d93SArnaldo Carvalho de Melo struct inet_sock *newinet; 4293df80d93SArnaldo Carvalho de Melo struct dccp6_sock *newdp6; 4303df80d93SArnaldo Carvalho de Melo struct sock *newsk; 4313df80d93SArnaldo Carvalho de Melo 4323df80d93SArnaldo Carvalho de Melo if (skb->protocol == htons(ETH_P_IP)) { 4333df80d93SArnaldo Carvalho de Melo /* 4343df80d93SArnaldo Carvalho de Melo * v6 mapped 4353df80d93SArnaldo Carvalho de Melo */ 4365e0724d0SEric Dumazet newsk = dccp_v4_request_recv_sock(sk, skb, req, dst, 4375e0724d0SEric Dumazet req_unhash, own_req); 4383df80d93SArnaldo Carvalho de Melo if (newsk == NULL) 4393df80d93SArnaldo Carvalho de Melo return NULL; 4403df80d93SArnaldo Carvalho de Melo 4413df80d93SArnaldo Carvalho de Melo newdp6 = (struct dccp6_sock *)newsk; 4423df80d93SArnaldo Carvalho de Melo newinet = inet_sk(newsk); 4433df80d93SArnaldo Carvalho de Melo newinet->pinet6 = &newdp6->inet6; 4443df80d93SArnaldo Carvalho de Melo newnp = inet6_sk(newsk); 4453df80d93SArnaldo Carvalho de Melo 4463df80d93SArnaldo Carvalho de Melo memcpy(newnp, np, sizeof(struct ipv6_pinfo)); 4473df80d93SArnaldo Carvalho de Melo 448d1e559d0SEric Dumazet newnp->saddr = newsk->sk_v6_rcv_saddr; 4493df80d93SArnaldo Carvalho de Melo 4503df80d93SArnaldo Carvalho de Melo inet_csk(newsk)->icsk_af_ops = &dccp_ipv6_mapped; 4513df80d93SArnaldo Carvalho de Melo newsk->sk_backlog_rcv = dccp_v4_do_rcv; 4523df80d93SArnaldo Carvalho de Melo newnp->pktoptions = NULL; 4533df80d93SArnaldo Carvalho de Melo newnp->opt = NULL; 45483eaddabSWANG Cong newnp->ipv6_mc_list = NULL; 45583eaddabSWANG Cong newnp->ipv6_ac_list = NULL; 45683eaddabSWANG Cong newnp->ipv6_fl_list = NULL; 457e0aa6770SEric Dumazet newnp->mcast_oif = inet_iif(skb); 458e0aa6770SEric Dumazet newnp->mcast_hops = ip_hdr(skb)->ttl; 4593df80d93SArnaldo Carvalho de Melo 4603df80d93SArnaldo Carvalho de Melo /* 4613df80d93SArnaldo Carvalho de Melo * No need to charge this sock to the relevant IPv6 refcnt debug socks count 4623df80d93SArnaldo Carvalho de Melo * here, dccp_create_openreq_child now does this for us, see the comment in 4633df80d93SArnaldo Carvalho de Melo * that function for the gory details. -acme 4643df80d93SArnaldo Carvalho de Melo */ 4653df80d93SArnaldo Carvalho de Melo 4663df80d93SArnaldo Carvalho de Melo /* It is tricky place. Until this moment IPv4 tcp 4673df80d93SArnaldo Carvalho de Melo worked with IPv6 icsk.icsk_af_ops. 4683df80d93SArnaldo Carvalho de Melo Sync it now. 4693df80d93SArnaldo Carvalho de Melo */ 470d83d8461SArnaldo Carvalho de Melo dccp_sync_mss(newsk, inet_csk(newsk)->icsk_pmtu_cookie); 4713df80d93SArnaldo Carvalho de Melo 4723df80d93SArnaldo Carvalho de Melo return newsk; 4733df80d93SArnaldo Carvalho de Melo } 4743df80d93SArnaldo Carvalho de Melo 4753df80d93SArnaldo Carvalho de Melo 4763df80d93SArnaldo Carvalho de Melo if (sk_acceptq_is_full(sk)) 4773df80d93SArnaldo Carvalho de Melo goto out_overflow; 4783df80d93SArnaldo Carvalho de Melo 479f76b33c3SEric Dumazet if (!dst) { 4804c9483b2SDavid S. Miller struct flowi6 fl6; 4813df80d93SArnaldo Carvalho de Melo 482f76b33c3SEric Dumazet dst = inet6_csk_route_req(sk, &fl6, req, IPPROTO_DCCP); 483f76b33c3SEric Dumazet if (!dst) 4843df80d93SArnaldo Carvalho de Melo goto out; 4853df80d93SArnaldo Carvalho de Melo } 4863df80d93SArnaldo Carvalho de Melo 4873df80d93SArnaldo Carvalho de Melo newsk = dccp_create_openreq_child(sk, req, skb); 4883df80d93SArnaldo Carvalho de Melo if (newsk == NULL) 489093d2823SBalazs Scheidler goto out_nonewsk; 4903df80d93SArnaldo Carvalho de Melo 4913df80d93SArnaldo Carvalho de Melo /* 4923df80d93SArnaldo Carvalho de Melo * No need to charge this sock to the relevant IPv6 refcnt debug socks 4933df80d93SArnaldo Carvalho de Melo * count here, dccp_create_openreq_child now does this for us, see the 4943df80d93SArnaldo Carvalho de Melo * comment in that function for the gory details. -acme 4953df80d93SArnaldo Carvalho de Melo */ 4963df80d93SArnaldo Carvalho de Melo 4976bd4f355SEric Dumazet ip6_dst_store(newsk, dst, NULL, NULL); 49845329e71SArnaldo Carvalho de Melo newsk->sk_route_caps = dst->dev->features & ~(NETIF_F_IP_CSUM | 49945329e71SArnaldo Carvalho de Melo NETIF_F_TSO); 5003df80d93SArnaldo Carvalho de Melo newdp6 = (struct dccp6_sock *)newsk; 5013df80d93SArnaldo Carvalho de Melo newinet = inet_sk(newsk); 5023df80d93SArnaldo Carvalho de Melo newinet->pinet6 = &newdp6->inet6; 5033df80d93SArnaldo Carvalho de Melo newnp = inet6_sk(newsk); 5043df80d93SArnaldo Carvalho de Melo 5053df80d93SArnaldo Carvalho de Melo memcpy(newnp, np, sizeof(struct ipv6_pinfo)); 5063df80d93SArnaldo Carvalho de Melo 507634fb979SEric Dumazet newsk->sk_v6_daddr = ireq->ir_v6_rmt_addr; 508634fb979SEric Dumazet newnp->saddr = ireq->ir_v6_loc_addr; 509634fb979SEric Dumazet newsk->sk_v6_rcv_saddr = ireq->ir_v6_loc_addr; 510634fb979SEric Dumazet newsk->sk_bound_dev_if = ireq->ir_iif; 5113df80d93SArnaldo Carvalho de Melo 5123df80d93SArnaldo Carvalho de Melo /* Now IPv6 options... 5133df80d93SArnaldo Carvalho de Melo 5143df80d93SArnaldo Carvalho de Melo First: no IPv4 options. 5153df80d93SArnaldo Carvalho de Melo */ 516f6d8bd05SEric Dumazet newinet->inet_opt = NULL; 5173df80d93SArnaldo Carvalho de Melo 5183df80d93SArnaldo Carvalho de Melo /* Clone RX bits */ 5193df80d93SArnaldo Carvalho de Melo newnp->rxopt.all = np->rxopt.all; 5203df80d93SArnaldo Carvalho de Melo 52183eaddabSWANG Cong newnp->ipv6_mc_list = NULL; 52283eaddabSWANG Cong newnp->ipv6_ac_list = NULL; 52383eaddabSWANG Cong newnp->ipv6_fl_list = NULL; 5243df80d93SArnaldo Carvalho de Melo newnp->pktoptions = NULL; 5253df80d93SArnaldo Carvalho de Melo newnp->opt = NULL; 5263df80d93SArnaldo Carvalho de Melo newnp->mcast_oif = inet6_iif(skb); 5270660e03fSArnaldo Carvalho de Melo newnp->mcast_hops = ipv6_hdr(skb)->hop_limit; 5283df80d93SArnaldo Carvalho de Melo 52945329e71SArnaldo Carvalho de Melo /* 53045329e71SArnaldo Carvalho de Melo * Clone native IPv6 options from listening socket (if any) 53145329e71SArnaldo Carvalho de Melo * 53245329e71SArnaldo Carvalho de Melo * Yes, keeping reference count would be much more clever, but we make 53345329e71SArnaldo Carvalho de Melo * one more one thing there: reattach optmem to newsk. 5343df80d93SArnaldo Carvalho de Melo */ 53556ac42bcSHuw Davies opt = ireq->ipv6_opt; 53656ac42bcSHuw Davies if (!opt) 53745f6fad8SEric Dumazet opt = rcu_dereference(np->opt); 53845f6fad8SEric Dumazet if (opt) { 53945f6fad8SEric Dumazet opt = ipv6_dup_options(newsk, opt); 54045f6fad8SEric Dumazet RCU_INIT_POINTER(newnp->opt, opt); 54145f6fad8SEric Dumazet } 542d83d8461SArnaldo Carvalho de Melo inet_csk(newsk)->icsk_ext_hdr_len = 0; 54345f6fad8SEric Dumazet if (opt) 54445f6fad8SEric Dumazet inet_csk(newsk)->icsk_ext_hdr_len = opt->opt_nflen + 54545f6fad8SEric Dumazet opt->opt_flen; 5463df80d93SArnaldo Carvalho de Melo 5473df80d93SArnaldo Carvalho de Melo dccp_sync_mss(newsk, dst_mtu(dst)); 5483df80d93SArnaldo Carvalho de Melo 549c720c7e8SEric Dumazet newinet->inet_daddr = newinet->inet_saddr = LOOPBACK4_IPV6; 550c720c7e8SEric Dumazet newinet->inet_rcv_saddr = LOOPBACK4_IPV6; 5513df80d93SArnaldo Carvalho de Melo 552093d2823SBalazs Scheidler if (__inet_inherit_port(sk, newsk) < 0) { 553e337e24dSChristoph Paasch inet_csk_prepare_forced_close(newsk); 554e337e24dSChristoph Paasch dccp_done(newsk); 555093d2823SBalazs Scheidler goto out; 556093d2823SBalazs Scheidler } 55701770a16SRicardo Dias *own_req = inet_ehash_nolisten(newsk, req_to_sk(req_unhash), NULL); 558ce105008SEric Dumazet /* Clone pktoptions received with SYN, if we own the req */ 559ce105008SEric Dumazet if (*own_req && ireq->pktopts) { 560ca43ccf4SKuniyuki Iwashima newnp->pktoptions = skb_clone_and_charge_r(ireq->pktopts, newsk); 561ce105008SEric Dumazet consume_skb(ireq->pktopts); 562ce105008SEric Dumazet ireq->pktopts = NULL; 563ce105008SEric Dumazet } 5643df80d93SArnaldo Carvalho de Melo 5653df80d93SArnaldo Carvalho de Melo return newsk; 5663df80d93SArnaldo Carvalho de Melo 5673df80d93SArnaldo Carvalho de Melo out_overflow: 56802a1d6e7SEric Dumazet __NET_INC_STATS(sock_net(sk), LINUX_MIB_LISTENOVERFLOWS); 569093d2823SBalazs Scheidler out_nonewsk: 570093d2823SBalazs Scheidler dst_release(dst); 5713df80d93SArnaldo Carvalho de Melo out: 57202a1d6e7SEric Dumazet __NET_INC_STATS(sock_net(sk), LINUX_MIB_LISTENDROPS); 5733df80d93SArnaldo Carvalho de Melo return NULL; 5743df80d93SArnaldo Carvalho de Melo } 5753df80d93SArnaldo Carvalho de Melo 5763df80d93SArnaldo Carvalho de Melo /* The socket must have it's spinlock held when we get 5773df80d93SArnaldo Carvalho de Melo * here. 5783df80d93SArnaldo Carvalho de Melo * 5793df80d93SArnaldo Carvalho de Melo * We have a potential double-lock case here, so even when 5803df80d93SArnaldo Carvalho de Melo * doing backlog processing we use the BH locking scheme. 5813df80d93SArnaldo Carvalho de Melo * This is because we cannot sleep with the original spinlock 5823df80d93SArnaldo Carvalho de Melo * held. 5833df80d93SArnaldo Carvalho de Melo */ 5843df80d93SArnaldo Carvalho de Melo static int dccp_v6_do_rcv(struct sock *sk, struct sk_buff *skb) 5853df80d93SArnaldo Carvalho de Melo { 5863df80d93SArnaldo Carvalho de Melo struct ipv6_pinfo *np = inet6_sk(sk); 5873df80d93SArnaldo Carvalho de Melo struct sk_buff *opt_skb = NULL; 5883df80d93SArnaldo Carvalho de Melo 5893df80d93SArnaldo Carvalho de Melo /* Imagine: socket is IPv6. IPv4 packet arrives, 5903df80d93SArnaldo Carvalho de Melo goes to IPv4 receive handler and backlogged. 5913df80d93SArnaldo Carvalho de Melo From backlog it always goes here. Kerboom... 5923df80d93SArnaldo Carvalho de Melo Fortunately, dccp_rcv_established and rcv_established 5933df80d93SArnaldo Carvalho de Melo handle them correctly, but it is not case with 5943df80d93SArnaldo Carvalho de Melo dccp_v6_hnd_req and dccp_v6_ctl_send_reset(). --ANK 5953df80d93SArnaldo Carvalho de Melo */ 5963df80d93SArnaldo Carvalho de Melo 5973df80d93SArnaldo Carvalho de Melo if (skb->protocol == htons(ETH_P_IP)) 5983df80d93SArnaldo Carvalho de Melo return dccp_v4_do_rcv(sk, skb); 5993df80d93SArnaldo Carvalho de Melo 600fda9ef5dSDmitry Mishin if (sk_filter(sk, skb)) 6013df80d93SArnaldo Carvalho de Melo goto discard; 6023df80d93SArnaldo Carvalho de Melo 6033df80d93SArnaldo Carvalho de Melo /* 60445329e71SArnaldo Carvalho de Melo * socket locking is here for SMP purposes as backlog rcv is currently 60545329e71SArnaldo Carvalho de Melo * called with bh processing disabled. 6063df80d93SArnaldo Carvalho de Melo */ 6073df80d93SArnaldo Carvalho de Melo 6083df80d93SArnaldo Carvalho de Melo /* Do Stevens' IPV6_PKTOPTIONS. 6093df80d93SArnaldo Carvalho de Melo 6103df80d93SArnaldo Carvalho de Melo Yes, guys, it is the only place in our code, where we 6113df80d93SArnaldo Carvalho de Melo may make it not affecting IPv4. 6123df80d93SArnaldo Carvalho de Melo The rest of code is protocol independent, 6133df80d93SArnaldo Carvalho de Melo and I do not like idea to uglify IPv4. 6143df80d93SArnaldo Carvalho de Melo 6153df80d93SArnaldo Carvalho de Melo Actually, all the idea behind IPV6_PKTOPTIONS 6163df80d93SArnaldo Carvalho de Melo looks not very well thought. For now we latch 6173df80d93SArnaldo Carvalho de Melo options, received in the last packet, enqueued 6183df80d93SArnaldo Carvalho de Melo by tcp. Feel free to propose better solution. 6193df80d93SArnaldo Carvalho de Melo --ANK (980728) 6203df80d93SArnaldo Carvalho de Melo */ 6213df80d93SArnaldo Carvalho de Melo if (np->rxopt.all) 622ca43ccf4SKuniyuki Iwashima opt_skb = skb_clone_and_charge_r(skb, sk); 6233df80d93SArnaldo Carvalho de Melo 6243df80d93SArnaldo Carvalho de Melo if (sk->sk_state == DCCP_OPEN) { /* Fast path */ 6253df80d93SArnaldo Carvalho de Melo if (dccp_rcv_established(sk, skb, dccp_hdr(skb), skb->len)) 6263df80d93SArnaldo Carvalho de Melo goto reset; 627323fbd0eSAndrii if (opt_skb) 628323fbd0eSAndrii goto ipv6_pktoptions; 6293df80d93SArnaldo Carvalho de Melo return 0; 6303df80d93SArnaldo Carvalho de Melo } 6313df80d93SArnaldo Carvalho de Melo 632d83ca5acSGerrit Renker /* 633d83ca5acSGerrit Renker * Step 3: Process LISTEN state 634d83ca5acSGerrit Renker * If S.state == LISTEN, 635d83ca5acSGerrit Renker * If P.type == Request or P contains a valid Init Cookie option, 636d83ca5acSGerrit Renker * (* Must scan the packet's options to check for Init 637d83ca5acSGerrit Renker * Cookies. Only Init Cookies are processed here, 638d83ca5acSGerrit Renker * however; other options are processed in Step 8. This 639d83ca5acSGerrit Renker * scan need only be performed if the endpoint uses Init 640d83ca5acSGerrit Renker * Cookies *) 641d83ca5acSGerrit Renker * (* Generate a new socket and switch to that socket *) 642d83ca5acSGerrit Renker * Set S := new socket for this port pair 643d83ca5acSGerrit Renker * S.state = RESPOND 644d83ca5acSGerrit Renker * Choose S.ISS (initial seqno) or set from Init Cookies 645d83ca5acSGerrit Renker * Initialize S.GAR := S.ISS 646d83ca5acSGerrit Renker * Set S.ISR, S.GSR, S.SWL, S.SWH from packet or Init Cookies 647d83ca5acSGerrit Renker * Continue with S.state == RESPOND 648d83ca5acSGerrit Renker * (* A Response packet will be generated in Step 11 *) 649d83ca5acSGerrit Renker * Otherwise, 650d83ca5acSGerrit Renker * Generate Reset(No Connection) unless P.type == Reset 651d83ca5acSGerrit Renker * Drop packet and return 652d83ca5acSGerrit Renker * 653d83ca5acSGerrit Renker * NOTE: the check for the packet types is done in 654d83ca5acSGerrit Renker * dccp_rcv_state_process 655d83ca5acSGerrit Renker */ 6563df80d93SArnaldo Carvalho de Melo 6573df80d93SArnaldo Carvalho de Melo if (dccp_rcv_state_process(sk, skb, dccp_hdr(skb), skb->len)) 6583df80d93SArnaldo Carvalho de Melo goto reset; 659323fbd0eSAndrii if (opt_skb) 660323fbd0eSAndrii goto ipv6_pktoptions; 6613df80d93SArnaldo Carvalho de Melo return 0; 6623df80d93SArnaldo Carvalho de Melo 6633df80d93SArnaldo Carvalho de Melo reset: 6646be49deaSJason Xing dccp_v6_ctl_send_reset(sk, skb, SK_RST_REASON_NOT_SPECIFIED); 6653df80d93SArnaldo Carvalho de Melo discard: 66645329e71SArnaldo Carvalho de Melo if (opt_skb != NULL) 6673df80d93SArnaldo Carvalho de Melo __kfree_skb(opt_skb); 6683df80d93SArnaldo Carvalho de Melo kfree_skb(skb); 6693df80d93SArnaldo Carvalho de Melo return 0; 670323fbd0eSAndrii 671323fbd0eSAndrii /* Handling IPV6_PKTOPTIONS skb the similar 672323fbd0eSAndrii * way it's done for net/ipv6/tcp_ipv6.c 673323fbd0eSAndrii */ 674323fbd0eSAndrii ipv6_pktoptions: 675323fbd0eSAndrii if (!((1 << sk->sk_state) & (DCCPF_CLOSED | DCCPF_LISTEN))) { 676323fbd0eSAndrii if (np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo) 677d2f011a0SEric Dumazet WRITE_ONCE(np->mcast_oif, inet6_iif(opt_skb)); 678323fbd0eSAndrii if (np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim) 6792da23eb0SEric Dumazet WRITE_ONCE(np->mcast_hops, ipv6_hdr(opt_skb)->hop_limit); 680323fbd0eSAndrii if (np->rxopt.bits.rxflow || np->rxopt.bits.rxtclass) 681323fbd0eSAndrii np->rcv_flowinfo = ip6_flowinfo(ipv6_hdr(opt_skb)); 6823cccda8dSEric Dumazet if (inet6_test_bit(REPFLOW, sk)) 683323fbd0eSAndrii np->flow_label = ip6_flowlabel(ipv6_hdr(opt_skb)); 684323fbd0eSAndrii if (ipv6_opt_accepted(sk, opt_skb, 685323fbd0eSAndrii &DCCP_SKB_CB(opt_skb)->header.h6)) { 686323fbd0eSAndrii memmove(IP6CB(opt_skb), 687323fbd0eSAndrii &DCCP_SKB_CB(opt_skb)->header.h6, 688323fbd0eSAndrii sizeof(struct inet6_skb_parm)); 689323fbd0eSAndrii opt_skb = xchg(&np->pktoptions, opt_skb); 690323fbd0eSAndrii } else { 691323fbd0eSAndrii __kfree_skb(opt_skb); 692323fbd0eSAndrii opt_skb = xchg(&np->pktoptions, NULL); 693323fbd0eSAndrii } 694323fbd0eSAndrii } 695323fbd0eSAndrii 696323fbd0eSAndrii kfree_skb(opt_skb); 697323fbd0eSAndrii return 0; 6983df80d93SArnaldo Carvalho de Melo } 6993df80d93SArnaldo Carvalho de Melo 700e5bbef20SHerbert Xu static int dccp_v6_rcv(struct sk_buff *skb) 7013df80d93SArnaldo Carvalho de Melo { 7023df80d93SArnaldo Carvalho de Melo const struct dccp_hdr *dh; 7033b24d854SEric Dumazet bool refcounted; 7043df80d93SArnaldo Carvalho de Melo struct sock *sk; 7056f4e5fffSGerrit Renker int min_cov; 7063df80d93SArnaldo Carvalho de Melo 7076f4e5fffSGerrit Renker /* Step 1: Check header basics */ 7083df80d93SArnaldo Carvalho de Melo 7093df80d93SArnaldo Carvalho de Melo if (dccp_invalid_packet(skb)) 7103df80d93SArnaldo Carvalho de Melo goto discard_it; 7113df80d93SArnaldo Carvalho de Melo 7126f4e5fffSGerrit Renker /* Step 1: If header checksum is incorrect, drop packet and return. */ 7130660e03fSArnaldo Carvalho de Melo if (dccp_v6_csum_finish(skb, &ipv6_hdr(skb)->saddr, 7140660e03fSArnaldo Carvalho de Melo &ipv6_hdr(skb)->daddr)) { 71559348b19SGerrit Renker DCCP_WARN("dropped packet with invalid checksum\n"); 7166f4e5fffSGerrit Renker goto discard_it; 7176f4e5fffSGerrit Renker } 7186f4e5fffSGerrit Renker 7193df80d93SArnaldo Carvalho de Melo dh = dccp_hdr(skb); 7203df80d93SArnaldo Carvalho de Melo 721fde20105SGerrit Renker DCCP_SKB_CB(skb)->dccpd_seq = dccp_hdr_seq(dh); 7223df80d93SArnaldo Carvalho de Melo DCCP_SKB_CB(skb)->dccpd_type = dh->dccph_type; 7233df80d93SArnaldo Carvalho de Melo 7243df80d93SArnaldo Carvalho de Melo if (dccp_packet_without_ack(skb)) 7253df80d93SArnaldo Carvalho de Melo DCCP_SKB_CB(skb)->dccpd_ack_seq = DCCP_PKT_WITHOUT_ACK_SEQ; 7263df80d93SArnaldo Carvalho de Melo else 7273df80d93SArnaldo Carvalho de Melo DCCP_SKB_CB(skb)->dccpd_ack_seq = dccp_hdr_ack_seq(skb); 7283df80d93SArnaldo Carvalho de Melo 7294bdc3d66SEric Dumazet lookup: 730a583636aSCraig Gallek sk = __inet6_lookup_skb(&dccp_hashinfo, skb, __dccp_hdr_len(dh), 731870c3151SEric Dumazet dh->dccph_sport, dh->dccph_dport, 7324297a0efSDavid Ahern inet6_iif(skb), 0, &refcounted); 7334bdc3d66SEric Dumazet if (!sk) { 734d23c7107SGerrit Renker dccp_pr_debug("failed to look up flow ID in table and " 735d23c7107SGerrit Renker "get corresponding socket\n"); 7363df80d93SArnaldo Carvalho de Melo goto no_dccp_socket; 737d23c7107SGerrit Renker } 7383df80d93SArnaldo Carvalho de Melo 7393df80d93SArnaldo Carvalho de Melo /* 7403df80d93SArnaldo Carvalho de Melo * Step 2: 7413df80d93SArnaldo Carvalho de Melo * ... or S.state == TIMEWAIT, 7423df80d93SArnaldo Carvalho de Melo * Generate Reset(No Connection) unless P.type == Reset 7433df80d93SArnaldo Carvalho de Melo * Drop packet and return 7443df80d93SArnaldo Carvalho de Melo */ 745d23c7107SGerrit Renker if (sk->sk_state == DCCP_TIME_WAIT) { 746d23c7107SGerrit Renker dccp_pr_debug("sk->sk_state == DCCP_TIME_WAIT: do_time_wait\n"); 747d23c7107SGerrit Renker inet_twsk_put(inet_twsk(sk)); 748d23c7107SGerrit Renker goto no_dccp_socket; 749d23c7107SGerrit Renker } 7503df80d93SArnaldo Carvalho de Melo 751079096f1SEric Dumazet if (sk->sk_state == DCCP_NEW_SYN_RECV) { 752079096f1SEric Dumazet struct request_sock *req = inet_reqsk(sk); 7537716682cSEric Dumazet struct sock *nsk; 754079096f1SEric Dumazet 755079096f1SEric Dumazet sk = req->rsk_listener; 7567716682cSEric Dumazet if (unlikely(sk->sk_state != DCCP_LISTEN)) { 757f03f2e15SEric Dumazet inet_csk_reqsk_queue_drop_and_put(sk, req); 7584bdc3d66SEric Dumazet goto lookup; 7594bdc3d66SEric Dumazet } 7607716682cSEric Dumazet sock_hold(sk); 7613b24d854SEric Dumazet refcounted = true; 7627716682cSEric Dumazet nsk = dccp_check_req(sk, skb, req); 763079096f1SEric Dumazet if (!nsk) { 764079096f1SEric Dumazet reqsk_put(req); 7657716682cSEric Dumazet goto discard_and_relse; 766079096f1SEric Dumazet } 767079096f1SEric Dumazet if (nsk == sk) { 768079096f1SEric Dumazet reqsk_put(req); 769079096f1SEric Dumazet } else if (dccp_child_process(sk, nsk, skb)) { 7706be49deaSJason Xing dccp_v6_ctl_send_reset(sk, skb, SK_RST_REASON_NOT_SPECIFIED); 7717716682cSEric Dumazet goto discard_and_relse; 772079096f1SEric Dumazet } else { 7737716682cSEric Dumazet sock_put(sk); 774079096f1SEric Dumazet return 0; 775079096f1SEric Dumazet } 776079096f1SEric Dumazet } 7776f4e5fffSGerrit Renker /* 7786f4e5fffSGerrit Renker * RFC 4340, sec. 9.2.1: Minimum Checksum Coverage 7796f4e5fffSGerrit Renker * o if MinCsCov = 0, only packets with CsCov = 0 are accepted 7806f4e5fffSGerrit Renker * o if MinCsCov > 0, also accept packets with CsCov >= MinCsCov 7816f4e5fffSGerrit Renker */ 7826f4e5fffSGerrit Renker min_cov = dccp_sk(sk)->dccps_pcrlen; 7836f4e5fffSGerrit Renker if (dh->dccph_cscov && (min_cov == 0 || dh->dccph_cscov < min_cov)) { 7846f4e5fffSGerrit Renker dccp_pr_debug("Packet CsCov %d does not satisfy MinCsCov %d\n", 7856f4e5fffSGerrit Renker dh->dccph_cscov, min_cov); 7866f4e5fffSGerrit Renker /* FIXME: send Data Dropped option (see also dccp_v4_rcv) */ 7876f4e5fffSGerrit Renker goto discard_and_relse; 7886f4e5fffSGerrit Renker } 7896f4e5fffSGerrit Renker 7903df80d93SArnaldo Carvalho de Melo if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb)) 7913df80d93SArnaldo Carvalho de Melo goto discard_and_relse; 792b0e214d2SMadhu Koriginja nf_reset_ct(skb); 7933df80d93SArnaldo Carvalho de Melo 794c3f24cfbSEric Dumazet return __sk_receive_skb(sk, skb, 1, dh->dccph_doff * 4, 795c3f24cfbSEric Dumazet refcounted) ? -1 : 0; 7963df80d93SArnaldo Carvalho de Melo 7973df80d93SArnaldo Carvalho de Melo no_dccp_socket: 7983df80d93SArnaldo Carvalho de Melo if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) 7993df80d93SArnaldo Carvalho de Melo goto discard_it; 8003df80d93SArnaldo Carvalho de Melo /* 8013df80d93SArnaldo Carvalho de Melo * Step 2: 802d83ca5acSGerrit Renker * If no socket ... 8033df80d93SArnaldo Carvalho de Melo * Generate Reset(No Connection) unless P.type == Reset 8043df80d93SArnaldo Carvalho de Melo * Drop packet and return 8053df80d93SArnaldo Carvalho de Melo */ 8063df80d93SArnaldo Carvalho de Melo if (dh->dccph_type != DCCP_PKT_RESET) { 8073df80d93SArnaldo Carvalho de Melo DCCP_SKB_CB(skb)->dccpd_reset_code = 8083df80d93SArnaldo Carvalho de Melo DCCP_RESET_CODE_NO_CONNECTION; 8096be49deaSJason Xing dccp_v6_ctl_send_reset(sk, skb, SK_RST_REASON_NOT_SPECIFIED); 8103df80d93SArnaldo Carvalho de Melo } 811d23c7107SGerrit Renker 8123df80d93SArnaldo Carvalho de Melo discard_it: 8133df80d93SArnaldo Carvalho de Melo kfree_skb(skb); 8143df80d93SArnaldo Carvalho de Melo return 0; 8153df80d93SArnaldo Carvalho de Melo 8163df80d93SArnaldo Carvalho de Melo discard_and_relse: 8173b24d854SEric Dumazet if (refcounted) 8183df80d93SArnaldo Carvalho de Melo sock_put(sk); 8193df80d93SArnaldo Carvalho de Melo goto discard_it; 8203df80d93SArnaldo Carvalho de Melo } 8213df80d93SArnaldo Carvalho de Melo 82273c9e02cSGerrit Renker static int dccp_v6_connect(struct sock *sk, struct sockaddr *uaddr, 82373c9e02cSGerrit Renker int addr_len) 82473c9e02cSGerrit Renker { 82573c9e02cSGerrit Renker struct sockaddr_in6 *usin = (struct sockaddr_in6 *)uaddr; 82673c9e02cSGerrit Renker struct inet_connection_sock *icsk = inet_csk(sk); 82773c9e02cSGerrit Renker struct inet_sock *inet = inet_sk(sk); 82873c9e02cSGerrit Renker struct ipv6_pinfo *np = inet6_sk(sk); 82973c9e02cSGerrit Renker struct dccp_sock *dp = dccp_sk(sk); 83020c59de2SArnaud Ebalard struct in6_addr *saddr = NULL, *final_p, final; 83145f6fad8SEric Dumazet struct ipv6_txoptions *opt; 8324c9483b2SDavid S. Miller struct flowi6 fl6; 83373c9e02cSGerrit Renker struct dst_entry *dst; 83473c9e02cSGerrit Renker int addr_type; 83573c9e02cSGerrit Renker int err; 83673c9e02cSGerrit Renker 83773c9e02cSGerrit Renker dp->dccps_role = DCCP_ROLE_CLIENT; 83873c9e02cSGerrit Renker 83973c9e02cSGerrit Renker if (addr_len < SIN6_LEN_RFC2133) 84073c9e02cSGerrit Renker return -EINVAL; 84173c9e02cSGerrit Renker 84273c9e02cSGerrit Renker if (usin->sin6_family != AF_INET6) 84373c9e02cSGerrit Renker return -EAFNOSUPPORT; 84473c9e02cSGerrit Renker 8454c9483b2SDavid S. Miller memset(&fl6, 0, sizeof(fl6)); 84673c9e02cSGerrit Renker 847859f8b26SEric Dumazet if (inet6_test_bit(SNDFLOW, sk)) { 8484c9483b2SDavid S. Miller fl6.flowlabel = usin->sin6_flowinfo & IPV6_FLOWINFO_MASK; 8494c9483b2SDavid S. Miller IP6_ECN_flow_init(fl6.flowlabel); 8504c9483b2SDavid S. Miller if (fl6.flowlabel & IPV6_FLOWLABEL_MASK) { 85173c9e02cSGerrit Renker struct ip6_flowlabel *flowlabel; 8524c9483b2SDavid S. Miller flowlabel = fl6_sock_lookup(sk, fl6.flowlabel); 85359c820b2SWillem de Bruijn if (IS_ERR(flowlabel)) 85473c9e02cSGerrit Renker return -EINVAL; 85573c9e02cSGerrit Renker fl6_sock_release(flowlabel); 85673c9e02cSGerrit Renker } 85773c9e02cSGerrit Renker } 85873c9e02cSGerrit Renker /* 85973c9e02cSGerrit Renker * connect() to INADDR_ANY means loopback (BSD'ism). 86073c9e02cSGerrit Renker */ 86173c9e02cSGerrit Renker if (ipv6_addr_any(&usin->sin6_addr)) 86273c9e02cSGerrit Renker usin->sin6_addr.s6_addr[15] = 1; 86373c9e02cSGerrit Renker 86473c9e02cSGerrit Renker addr_type = ipv6_addr_type(&usin->sin6_addr); 86573c9e02cSGerrit Renker 86673c9e02cSGerrit Renker if (addr_type & IPV6_ADDR_MULTICAST) 86773c9e02cSGerrit Renker return -ENETUNREACH; 86873c9e02cSGerrit Renker 86973c9e02cSGerrit Renker if (addr_type & IPV6_ADDR_LINKLOCAL) { 87073c9e02cSGerrit Renker if (addr_len >= sizeof(struct sockaddr_in6) && 87173c9e02cSGerrit Renker usin->sin6_scope_id) { 87273c9e02cSGerrit Renker /* If interface is set while binding, indices 87373c9e02cSGerrit Renker * must coincide. 87473c9e02cSGerrit Renker */ 87573c9e02cSGerrit Renker if (sk->sk_bound_dev_if && 87673c9e02cSGerrit Renker sk->sk_bound_dev_if != usin->sin6_scope_id) 87773c9e02cSGerrit Renker return -EINVAL; 87873c9e02cSGerrit Renker 87973c9e02cSGerrit Renker sk->sk_bound_dev_if = usin->sin6_scope_id; 88073c9e02cSGerrit Renker } 88173c9e02cSGerrit Renker 88273c9e02cSGerrit Renker /* Connect to link-local address requires an interface */ 88373c9e02cSGerrit Renker if (!sk->sk_bound_dev_if) 88473c9e02cSGerrit Renker return -EINVAL; 88573c9e02cSGerrit Renker } 88673c9e02cSGerrit Renker 887efe4208fSEric Dumazet sk->sk_v6_daddr = usin->sin6_addr; 8884c9483b2SDavid S. Miller np->flow_label = fl6.flowlabel; 88973c9e02cSGerrit Renker 89073c9e02cSGerrit Renker /* 89173c9e02cSGerrit Renker * DCCP over IPv4 89273c9e02cSGerrit Renker */ 89373c9e02cSGerrit Renker if (addr_type == IPV6_ADDR_MAPPED) { 89473c9e02cSGerrit Renker u32 exthdrlen = icsk->icsk_ext_hdr_len; 89573c9e02cSGerrit Renker struct sockaddr_in sin; 89673c9e02cSGerrit Renker 8978e5443d2SDenis Kirjanov net_dbg_ratelimited("connect: ipv4 mapped\n"); 89873c9e02cSGerrit Renker 89989e9c728SKuniyuki Iwashima if (ipv6_only_sock(sk)) 90073c9e02cSGerrit Renker return -ENETUNREACH; 90173c9e02cSGerrit Renker 90273c9e02cSGerrit Renker sin.sin_family = AF_INET; 90373c9e02cSGerrit Renker sin.sin_port = usin->sin6_port; 90473c9e02cSGerrit Renker sin.sin_addr.s_addr = usin->sin6_addr.s6_addr32[3]; 90573c9e02cSGerrit Renker 90673c9e02cSGerrit Renker icsk->icsk_af_ops = &dccp_ipv6_mapped; 90773c9e02cSGerrit Renker sk->sk_backlog_rcv = dccp_v4_do_rcv; 90873c9e02cSGerrit Renker 90973c9e02cSGerrit Renker err = dccp_v4_connect(sk, (struct sockaddr *)&sin, sizeof(sin)); 91073c9e02cSGerrit Renker if (err) { 91173c9e02cSGerrit Renker icsk->icsk_ext_hdr_len = exthdrlen; 91273c9e02cSGerrit Renker icsk->icsk_af_ops = &dccp_ipv6_af_ops; 91373c9e02cSGerrit Renker sk->sk_backlog_rcv = dccp_v6_do_rcv; 91473c9e02cSGerrit Renker goto failure; 91573c9e02cSGerrit Renker } 916d1e559d0SEric Dumazet np->saddr = sk->sk_v6_rcv_saddr; 91773c9e02cSGerrit Renker return err; 91873c9e02cSGerrit Renker } 91973c9e02cSGerrit Renker 920efe4208fSEric Dumazet if (!ipv6_addr_any(&sk->sk_v6_rcv_saddr)) 921efe4208fSEric Dumazet saddr = &sk->sk_v6_rcv_saddr; 92273c9e02cSGerrit Renker 9234c9483b2SDavid S. Miller fl6.flowi6_proto = IPPROTO_DCCP; 924efe4208fSEric Dumazet fl6.daddr = sk->sk_v6_daddr; 9254e3fd7a0SAlexey Dobriyan fl6.saddr = saddr ? *saddr : np->saddr; 9264c9483b2SDavid S. Miller fl6.flowi6_oif = sk->sk_bound_dev_if; 9271958b856SDavid S. Miller fl6.fl6_dport = usin->sin6_port; 9281958b856SDavid S. Miller fl6.fl6_sport = inet->inet_sport; 9293df98d79SPaul Moore security_sk_classify_flow(sk, flowi6_to_flowi_common(&fl6)); 93073c9e02cSGerrit Renker 9311e1d04e6SHannes Frederic Sowa opt = rcu_dereference_protected(np->opt, lockdep_sock_is_held(sk)); 93245f6fad8SEric Dumazet final_p = fl6_update_dst(&fl6, opt, &final); 93373c9e02cSGerrit Renker 934c4e85f73SSabrina Dubroca dst = ip6_dst_lookup_flow(sock_net(sk), sk, &fl6, final_p); 93568d0c6d3SDavid S. Miller if (IS_ERR(dst)) { 93668d0c6d3SDavid S. Miller err = PTR_ERR(dst); 93773c9e02cSGerrit Renker goto failure; 93814e50e57SDavid S. Miller } 93973c9e02cSGerrit Renker 94073c9e02cSGerrit Renker if (saddr == NULL) { 9414c9483b2SDavid S. Miller saddr = &fl6.saddr; 94228044fc1SJoanne Koong 9438c5dae4cSKuniyuki Iwashima err = inet_bhash2_update_saddr(sk, saddr, AF_INET6); 9448c5dae4cSKuniyuki Iwashima if (err) 94528044fc1SJoanne Koong goto failure; 94628044fc1SJoanne Koong } 94773c9e02cSGerrit Renker 94873c9e02cSGerrit Renker /* set the source address */ 9494e3fd7a0SAlexey Dobriyan np->saddr = *saddr; 950c720c7e8SEric Dumazet inet->inet_rcv_saddr = LOOPBACK4_IPV6; 95173c9e02cSGerrit Renker 9526bd4f355SEric Dumazet ip6_dst_store(sk, dst, NULL, NULL); 95373c9e02cSGerrit Renker 95473c9e02cSGerrit Renker icsk->icsk_ext_hdr_len = 0; 95545f6fad8SEric Dumazet if (opt) 95645f6fad8SEric Dumazet icsk->icsk_ext_hdr_len = opt->opt_flen + opt->opt_nflen; 95773c9e02cSGerrit Renker 958c720c7e8SEric Dumazet inet->inet_dport = usin->sin6_port; 95973c9e02cSGerrit Renker 96073c9e02cSGerrit Renker dccp_set_state(sk, DCCP_REQUESTING); 96173c9e02cSGerrit Renker err = inet6_hash_connect(&dccp_death_row, sk); 96273c9e02cSGerrit Renker if (err) 96373c9e02cSGerrit Renker goto late_failure; 964d7f7365fSGerrit Renker 965d7f7365fSGerrit Renker dp->dccps_iss = secure_dccpv6_sequence_number(np->saddr.s6_addr32, 966efe4208fSEric Dumazet sk->sk_v6_daddr.s6_addr32, 967c720c7e8SEric Dumazet inet->inet_sport, 968c720c7e8SEric Dumazet inet->inet_dport); 96973c9e02cSGerrit Renker err = dccp_connect(sk); 97073c9e02cSGerrit Renker if (err) 97173c9e02cSGerrit Renker goto late_failure; 97273c9e02cSGerrit Renker 97373c9e02cSGerrit Renker return 0; 97473c9e02cSGerrit Renker 97573c9e02cSGerrit Renker late_failure: 97673c9e02cSGerrit Renker dccp_set_state(sk, DCCP_CLOSED); 977e0833d1fSKuniyuki Iwashima inet_bhash2_reset_saddr(sk); 97873c9e02cSGerrit Renker __sk_dst_reset(sk); 97973c9e02cSGerrit Renker failure: 980c720c7e8SEric Dumazet inet->inet_dport = 0; 98173c9e02cSGerrit Renker sk->sk_route_caps = 0; 98273c9e02cSGerrit Renker return err; 98373c9e02cSGerrit Renker } 98473c9e02cSGerrit Renker 9853b401a81SStephen Hemminger static const struct inet_connection_sock_af_ops dccp_ipv6_af_ops = { 9863df80d93SArnaldo Carvalho de Melo .queue_xmit = inet6_csk_xmit, 9873df80d93SArnaldo Carvalho de Melo .send_check = dccp_v6_send_check, 9883df80d93SArnaldo Carvalho de Melo .rebuild_header = inet6_sk_rebuild_header, 9893df80d93SArnaldo Carvalho de Melo .conn_request = dccp_v6_conn_request, 9903df80d93SArnaldo Carvalho de Melo .syn_recv_sock = dccp_v6_request_recv_sock, 9913df80d93SArnaldo Carvalho de Melo .net_header_len = sizeof(struct ipv6hdr), 9923df80d93SArnaldo Carvalho de Melo .setsockopt = ipv6_setsockopt, 9933df80d93SArnaldo Carvalho de Melo .getsockopt = ipv6_getsockopt, 994543d9cfeSArnaldo Carvalho de Melo .addr2sockaddr = inet6_csk_addr2sockaddr, 995543d9cfeSArnaldo Carvalho de Melo .sockaddr_len = sizeof(struct sockaddr_in6), 9963df80d93SArnaldo Carvalho de Melo }; 9973df80d93SArnaldo Carvalho de Melo 9983df80d93SArnaldo Carvalho de Melo /* 9993df80d93SArnaldo Carvalho de Melo * DCCP over IPv4 via INET6 API 10003df80d93SArnaldo Carvalho de Melo */ 10013b401a81SStephen Hemminger static const struct inet_connection_sock_af_ops dccp_ipv6_mapped = { 10023df80d93SArnaldo Carvalho de Melo .queue_xmit = ip_queue_xmit, 10033df80d93SArnaldo Carvalho de Melo .send_check = dccp_v4_send_check, 10043df80d93SArnaldo Carvalho de Melo .rebuild_header = inet_sk_rebuild_header, 10053df80d93SArnaldo Carvalho de Melo .conn_request = dccp_v6_conn_request, 10063df80d93SArnaldo Carvalho de Melo .syn_recv_sock = dccp_v6_request_recv_sock, 10073df80d93SArnaldo Carvalho de Melo .net_header_len = sizeof(struct iphdr), 10083df80d93SArnaldo Carvalho de Melo .setsockopt = ipv6_setsockopt, 10093df80d93SArnaldo Carvalho de Melo .getsockopt = ipv6_getsockopt, 1010543d9cfeSArnaldo Carvalho de Melo .addr2sockaddr = inet6_csk_addr2sockaddr, 1011543d9cfeSArnaldo Carvalho de Melo .sockaddr_len = sizeof(struct sockaddr_in6), 10123df80d93SArnaldo Carvalho de Melo }; 10133df80d93SArnaldo Carvalho de Melo 10141651951eSKuniyuki Iwashima static void dccp_v6_sk_destruct(struct sock *sk) 10151651951eSKuniyuki Iwashima { 10161651951eSKuniyuki Iwashima dccp_destruct_common(sk); 10171651951eSKuniyuki Iwashima inet6_sock_destruct(sk); 10181651951eSKuniyuki Iwashima } 10191651951eSKuniyuki Iwashima 10203df80d93SArnaldo Carvalho de Melo /* NOTE: A lot of things set to zero explicitly by call to 10213df80d93SArnaldo Carvalho de Melo * sk_alloc() so need not be done here. 10223df80d93SArnaldo Carvalho de Melo */ 10233df80d93SArnaldo Carvalho de Melo static int dccp_v6_init_sock(struct sock *sk) 10243df80d93SArnaldo Carvalho de Melo { 102572478873SArnaldo Carvalho de Melo static __u8 dccp_v6_ctl_sock_initialized; 102672478873SArnaldo Carvalho de Melo int err = dccp_init_sock(sk, dccp_v6_ctl_sock_initialized); 10273df80d93SArnaldo Carvalho de Melo 102872478873SArnaldo Carvalho de Melo if (err == 0) { 102972478873SArnaldo Carvalho de Melo if (unlikely(!dccp_v6_ctl_sock_initialized)) 103072478873SArnaldo Carvalho de Melo dccp_v6_ctl_sock_initialized = 1; 10313df80d93SArnaldo Carvalho de Melo inet_csk(sk)->icsk_af_ops = &dccp_ipv6_af_ops; 10321651951eSKuniyuki Iwashima sk->sk_destruct = dccp_v6_sk_destruct; 103372478873SArnaldo Carvalho de Melo } 10343df80d93SArnaldo Carvalho de Melo 10353df80d93SArnaldo Carvalho de Melo return err; 10363df80d93SArnaldo Carvalho de Melo } 10373df80d93SArnaldo Carvalho de Melo 103873c9e02cSGerrit Renker static struct timewait_sock_ops dccp6_timewait_sock_ops = { 103973c9e02cSGerrit Renker .twsk_obj_size = sizeof(struct dccp6_timewait_sock), 104073c9e02cSGerrit Renker }; 104173c9e02cSGerrit Renker 10423df80d93SArnaldo Carvalho de Melo static struct proto dccp_v6_prot = { 10433df80d93SArnaldo Carvalho de Melo .name = "DCCPv6", 10443df80d93SArnaldo Carvalho de Melo .owner = THIS_MODULE, 10453df80d93SArnaldo Carvalho de Melo .close = dccp_close, 10463df80d93SArnaldo Carvalho de Melo .connect = dccp_v6_connect, 10473df80d93SArnaldo Carvalho de Melo .disconnect = dccp_disconnect, 10483df80d93SArnaldo Carvalho de Melo .ioctl = dccp_ioctl, 10493df80d93SArnaldo Carvalho de Melo .init = dccp_v6_init_sock, 10503df80d93SArnaldo Carvalho de Melo .setsockopt = dccp_setsockopt, 10513df80d93SArnaldo Carvalho de Melo .getsockopt = dccp_getsockopt, 10523df80d93SArnaldo Carvalho de Melo .sendmsg = dccp_sendmsg, 10533df80d93SArnaldo Carvalho de Melo .recvmsg = dccp_recvmsg, 10543df80d93SArnaldo Carvalho de Melo .backlog_rcv = dccp_v6_do_rcv, 1055496611d7SCraig Gallek .hash = inet6_hash, 1056ab1e0a13SArnaldo Carvalho de Melo .unhash = inet_unhash, 10573df80d93SArnaldo Carvalho de Melo .accept = inet_csk_accept, 1058ab1e0a13SArnaldo Carvalho de Melo .get_port = inet_csk_get_port, 10593df80d93SArnaldo Carvalho de Melo .shutdown = dccp_shutdown, 10601651951eSKuniyuki Iwashima .destroy = dccp_destroy_sock, 10613df80d93SArnaldo Carvalho de Melo .orphan_count = &dccp_orphan_count, 10623df80d93SArnaldo Carvalho de Melo .max_header = MAX_DCCP_HEADER, 10633df80d93SArnaldo Carvalho de Melo .obj_size = sizeof(struct dccp6_sock), 1064f5f80e32SEric Dumazet .ipv6_pinfo_offset = offsetof(struct dccp6_sock, inet6), 10655f0d5a3aSPaul E. McKenney .slab_flags = SLAB_TYPESAFE_BY_RCU, 10663df80d93SArnaldo Carvalho de Melo .rsk_prot = &dccp6_request_sock_ops, 10676d6ee43eSArnaldo Carvalho de Melo .twsk_prot = &dccp6_timewait_sock_ops, 106839d8cda7SPavel Emelyanov .h.hashinfo = &dccp_hashinfo, 10693df80d93SArnaldo Carvalho de Melo }; 10703df80d93SArnaldo Carvalho de Melo 107141135cc8SAlexey Dobriyan static const struct inet6_protocol dccp_v6_protocol = { 10723df80d93SArnaldo Carvalho de Melo .handler = dccp_v6_rcv, 10733df80d93SArnaldo Carvalho de Melo .err_handler = dccp_v6_err, 10743df80d93SArnaldo Carvalho de Melo .flags = INET6_PROTO_NOPOLICY | INET6_PROTO_FINAL, 10753df80d93SArnaldo Carvalho de Melo }; 10763df80d93SArnaldo Carvalho de Melo 10775708e868SAlexey Dobriyan static const struct proto_ops inet6_dccp_ops = { 10783df80d93SArnaldo Carvalho de Melo .family = PF_INET6, 10793df80d93SArnaldo Carvalho de Melo .owner = THIS_MODULE, 10803df80d93SArnaldo Carvalho de Melo .release = inet6_release, 10813df80d93SArnaldo Carvalho de Melo .bind = inet6_bind, 10823df80d93SArnaldo Carvalho de Melo .connect = inet_stream_connect, 10833df80d93SArnaldo Carvalho de Melo .socketpair = sock_no_socketpair, 10843df80d93SArnaldo Carvalho de Melo .accept = inet_accept, 10853df80d93SArnaldo Carvalho de Melo .getname = inet6_getname, 1086a11e1d43SLinus Torvalds .poll = dccp_poll, 10873df80d93SArnaldo Carvalho de Melo .ioctl = inet6_ioctl, 1088c7cbdbf2SArnd Bergmann .gettstamp = sock_gettstamp, 10893df80d93SArnaldo Carvalho de Melo .listen = inet_dccp_listen, 10903df80d93SArnaldo Carvalho de Melo .shutdown = inet_shutdown, 10913df80d93SArnaldo Carvalho de Melo .setsockopt = sock_common_setsockopt, 10923df80d93SArnaldo Carvalho de Melo .getsockopt = sock_common_getsockopt, 10933df80d93SArnaldo Carvalho de Melo .sendmsg = inet_sendmsg, 10943df80d93SArnaldo Carvalho de Melo .recvmsg = sock_common_recvmsg, 10953df80d93SArnaldo Carvalho de Melo .mmap = sock_no_mmap, 1096543d9cfeSArnaldo Carvalho de Melo #ifdef CONFIG_COMPAT 10973986912fSChristoph Hellwig .compat_ioctl = inet6_compat_ioctl, 1098543d9cfeSArnaldo Carvalho de Melo #endif 10993df80d93SArnaldo Carvalho de Melo }; 11003df80d93SArnaldo Carvalho de Melo 11013df80d93SArnaldo Carvalho de Melo static struct inet_protosw dccp_v6_protosw = { 11023df80d93SArnaldo Carvalho de Melo .type = SOCK_DCCP, 11033df80d93SArnaldo Carvalho de Melo .protocol = IPPROTO_DCCP, 11043df80d93SArnaldo Carvalho de Melo .prot = &dccp_v6_prot, 11053df80d93SArnaldo Carvalho de Melo .ops = &inet6_dccp_ops, 1106d83d8461SArnaldo Carvalho de Melo .flags = INET_PROTOSW_ICSK, 11073df80d93SArnaldo Carvalho de Melo }; 11083df80d93SArnaldo Carvalho de Melo 11092c8c1e72SAlexey Dobriyan static int __net_init dccp_v6_init_net(struct net *net) 11108231bd27SPavel Emelyanov { 1111b98b3304SFlorian Westphal struct dccp_v6_pernet *pn = net_generic(net, dccp_v6_pernet_id); 1112b98b3304SFlorian Westphal 1113d14a0ebdSGerrit Renker if (dccp_hashinfo.bhash == NULL) 1114d14a0ebdSGerrit Renker return -ESOCKTNOSUPPORT; 1115334527d3SPavel Emelyanov 1116b98b3304SFlorian Westphal return inet_ctl_sock_create(&pn->v6_ctl_sk, PF_INET6, 1117334527d3SPavel Emelyanov SOCK_DCCP, IPPROTO_DCCP, net); 11188231bd27SPavel Emelyanov } 11198231bd27SPavel Emelyanov 11202c8c1e72SAlexey Dobriyan static void __net_exit dccp_v6_exit_net(struct net *net) 11218231bd27SPavel Emelyanov { 1122b98b3304SFlorian Westphal struct dccp_v6_pernet *pn = net_generic(net, dccp_v6_pernet_id); 1123b98b3304SFlorian Westphal 1124b98b3304SFlorian Westphal inet_ctl_sock_destroy(pn->v6_ctl_sk); 11258231bd27SPavel Emelyanov } 11268231bd27SPavel Emelyanov 11278231bd27SPavel Emelyanov static struct pernet_operations dccp_v6_ops = { 11288231bd27SPavel Emelyanov .init = dccp_v6_init_net, 11298231bd27SPavel Emelyanov .exit = dccp_v6_exit_net, 1130b98b3304SFlorian Westphal .id = &dccp_v6_pernet_id, 1131b98b3304SFlorian Westphal .size = sizeof(struct dccp_v6_pernet), 11328231bd27SPavel Emelyanov }; 11338231bd27SPavel Emelyanov 11343df80d93SArnaldo Carvalho de Melo static int __init dccp_v6_init(void) 11353df80d93SArnaldo Carvalho de Melo { 11363df80d93SArnaldo Carvalho de Melo int err = proto_register(&dccp_v6_prot, 1); 11373df80d93SArnaldo Carvalho de Melo 1138a0f9a4c2SXin Long if (err) 11393df80d93SArnaldo Carvalho de Melo goto out; 11403df80d93SArnaldo Carvalho de Melo 11413df80d93SArnaldo Carvalho de Melo inet6_register_protosw(&dccp_v6_protosw); 114272478873SArnaldo Carvalho de Melo 11438231bd27SPavel Emelyanov err = register_pernet_subsys(&dccp_v6_ops); 1144a0f9a4c2SXin Long if (err) 11458231bd27SPavel Emelyanov goto out_destroy_ctl_sock; 1146a0f9a4c2SXin Long 1147a0f9a4c2SXin Long err = inet6_add_protocol(&dccp_v6_protocol, IPPROTO_DCCP); 1148a0f9a4c2SXin Long if (err) 1149a0f9a4c2SXin Long goto out_unregister_proto; 1150a0f9a4c2SXin Long 11513df80d93SArnaldo Carvalho de Melo out: 11523df80d93SArnaldo Carvalho de Melo return err; 11533df80d93SArnaldo Carvalho de Melo out_unregister_proto: 1154a0f9a4c2SXin Long unregister_pernet_subsys(&dccp_v6_ops); 1155a0f9a4c2SXin Long out_destroy_ctl_sock: 1156a0f9a4c2SXin Long inet6_unregister_protosw(&dccp_v6_protosw); 11573df80d93SArnaldo Carvalho de Melo proto_unregister(&dccp_v6_prot); 11583df80d93SArnaldo Carvalho de Melo goto out; 11593df80d93SArnaldo Carvalho de Melo } 11603df80d93SArnaldo Carvalho de Melo 11613df80d93SArnaldo Carvalho de Melo static void __exit dccp_v6_exit(void) 11623df80d93SArnaldo Carvalho de Melo { 11633df80d93SArnaldo Carvalho de Melo inet6_del_protocol(&dccp_v6_protocol, IPPROTO_DCCP); 1164a0f9a4c2SXin Long unregister_pernet_subsys(&dccp_v6_ops); 11653df80d93SArnaldo Carvalho de Melo inet6_unregister_protosw(&dccp_v6_protosw); 11663df80d93SArnaldo Carvalho de Melo proto_unregister(&dccp_v6_prot); 11673df80d93SArnaldo Carvalho de Melo } 11683df80d93SArnaldo Carvalho de Melo 11693df80d93SArnaldo Carvalho de Melo module_init(dccp_v6_init); 11703df80d93SArnaldo Carvalho de Melo module_exit(dccp_v6_exit); 11713df80d93SArnaldo Carvalho de Melo 11723df80d93SArnaldo Carvalho de Melo /* 11733df80d93SArnaldo Carvalho de Melo * __stringify doesn't likes enums, so use SOCK_DCCP (6) and IPPROTO_DCCP (33) 11743df80d93SArnaldo Carvalho de Melo * values directly, Also cover the case where the protocol is not specified, 11753df80d93SArnaldo Carvalho de Melo * i.e. net-pf-PF_INET6-proto-0-type-SOCK_DCCP 11763df80d93SArnaldo Carvalho de Melo */ 11777131c6c7SJean Delvare MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_INET6, 33, 6); 11787131c6c7SJean Delvare MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_INET6, 0, 6); 11793df80d93SArnaldo Carvalho de Melo MODULE_LICENSE("GPL"); 11803df80d93SArnaldo Carvalho de Melo MODULE_AUTHOR("Arnaldo Carvalho de Melo <acme@mandriva.com>"); 11813df80d93SArnaldo Carvalho de Melo MODULE_DESCRIPTION("DCCPv6 - Datagram Congestion Controlled Protocol"); 1182