13df80d93SArnaldo Carvalho de Melo /* 23df80d93SArnaldo Carvalho de Melo * DCCP over IPv6 33df80d93SArnaldo Carvalho de Melo * Linux INET6 implementation 43df80d93SArnaldo Carvalho de Melo * 53df80d93SArnaldo Carvalho de Melo * Based on net/dccp6/ipv6.c 63df80d93SArnaldo Carvalho de Melo * 73df80d93SArnaldo Carvalho de Melo * Arnaldo Carvalho de Melo <acme@ghostprotocols.net> 83df80d93SArnaldo Carvalho de Melo * 93df80d93SArnaldo Carvalho de Melo * This program is free software; you can redistribute it and/or 103df80d93SArnaldo Carvalho de Melo * modify it under the terms of the GNU General Public License 113df80d93SArnaldo Carvalho de Melo * as published by the Free Software Foundation; either version 123df80d93SArnaldo Carvalho de Melo * 2 of the License, or (at your option) any later version. 133df80d93SArnaldo Carvalho de Melo */ 143df80d93SArnaldo Carvalho de Melo 153df80d93SArnaldo Carvalho de Melo #include <linux/module.h> 163df80d93SArnaldo Carvalho de Melo #include <linux/random.h> 175a0e3ad6STejun Heo #include <linux/slab.h> 183df80d93SArnaldo Carvalho de Melo #include <linux/xfrm.h> 193df80d93SArnaldo Carvalho de Melo 203df80d93SArnaldo Carvalho de Melo #include <net/addrconf.h> 213df80d93SArnaldo Carvalho de Melo #include <net/inet_common.h> 223df80d93SArnaldo Carvalho de Melo #include <net/inet_hashtables.h> 2314c85021SArnaldo Carvalho de Melo #include <net/inet_sock.h> 243df80d93SArnaldo Carvalho de Melo #include <net/inet6_connection_sock.h> 253df80d93SArnaldo Carvalho de Melo #include <net/inet6_hashtables.h> 263df80d93SArnaldo Carvalho de Melo #include <net/ip6_route.h> 273df80d93SArnaldo Carvalho de Melo #include <net/ipv6.h> 283df80d93SArnaldo Carvalho de Melo #include <net/protocol.h> 293df80d93SArnaldo Carvalho de Melo #include <net/transp_v6.h> 30aa0e4e4aSDavid S. Miller #include <net/ip6_checksum.h> 313df80d93SArnaldo Carvalho de Melo #include <net/xfrm.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 3713f51d82SPavel Emelyanov /* The per-net dccp.v6_ctl_sk is used for sending RSTs and ACKs */ 3872478873SArnaldo Carvalho de Melo 393b401a81SStephen Hemminger static const struct inet_connection_sock_af_ops dccp_ipv6_mapped; 403b401a81SStephen Hemminger static const struct inet_connection_sock_af_ops dccp_ipv6_af_ops; 413df80d93SArnaldo Carvalho de Melo 423df80d93SArnaldo Carvalho de Melo static void dccp_v6_hash(struct sock *sk) 433df80d93SArnaldo Carvalho de Melo { 443df80d93SArnaldo Carvalho de Melo if (sk->sk_state != DCCP_CLOSED) { 453df80d93SArnaldo Carvalho de Melo if (inet_csk(sk)->icsk_af_ops == &dccp_ipv6_mapped) { 46ab1e0a13SArnaldo Carvalho de Melo inet_hash(sk); 473df80d93SArnaldo Carvalho de Melo return; 483df80d93SArnaldo Carvalho de Melo } 493df80d93SArnaldo Carvalho de Melo local_bh_disable(); 509327f705SEric Dumazet __inet6_hash(sk, NULL); 513df80d93SArnaldo Carvalho de Melo local_bh_enable(); 523df80d93SArnaldo Carvalho de Melo } 533df80d93SArnaldo Carvalho de Melo } 543df80d93SArnaldo Carvalho de Melo 556f4e5fffSGerrit Renker /* add pseudo-header to DCCP checksum stored in skb->csum */ 56868c86bcSAl Viro static inline __sum16 dccp_v6_csum_finish(struct sk_buff *skb, 573df80d93SArnaldo Carvalho de Melo struct in6_addr *saddr, 586f4e5fffSGerrit Renker struct in6_addr *daddr) 593df80d93SArnaldo Carvalho de Melo { 606f4e5fffSGerrit Renker return csum_ipv6_magic(saddr, daddr, skb->len, IPPROTO_DCCP, skb->csum); 616f4e5fffSGerrit Renker } 626f4e5fffSGerrit Renker 63bb296246SHerbert Xu static inline void dccp_v6_send_check(struct sock *sk, struct sk_buff *skb) 646f4e5fffSGerrit Renker { 656f4e5fffSGerrit Renker struct ipv6_pinfo *np = inet6_sk(sk); 666f4e5fffSGerrit Renker struct dccp_hdr *dh = dccp_hdr(skb); 676f4e5fffSGerrit Renker 686f4e5fffSGerrit Renker dccp_csum_outgoing(skb); 696f4e5fffSGerrit Renker dh->dccph_checksum = dccp_v6_csum_finish(skb, &np->saddr, &np->daddr); 703df80d93SArnaldo Carvalho de Melo } 713df80d93SArnaldo Carvalho de Melo 727d533f94SAl Viro static inline __u32 secure_dccpv6_sequence_number(__be32 *saddr, __be32 *daddr, 737d533f94SAl Viro __be16 sport, __be16 dport ) 743df80d93SArnaldo Carvalho de Melo { 75d7f7365fSGerrit Renker return secure_tcpv6_sequence_number(saddr, daddr, sport, dport); 76d7f7365fSGerrit Renker } 77d7f7365fSGerrit Renker 78d7f7365fSGerrit Renker static inline __u32 dccp_v6_init_sequence(struct sk_buff *skb) 79d7f7365fSGerrit Renker { 800660e03fSArnaldo Carvalho de Melo return secure_dccpv6_sequence_number(ipv6_hdr(skb)->daddr.s6_addr32, 810660e03fSArnaldo Carvalho de Melo ipv6_hdr(skb)->saddr.s6_addr32, 82865e9022SGerrit Renker dccp_hdr(skb)->dccph_dport, 83865e9022SGerrit Renker dccp_hdr(skb)->dccph_sport ); 84d7f7365fSGerrit Renker 853df80d93SArnaldo Carvalho de Melo } 863df80d93SArnaldo Carvalho de Melo 873df80d93SArnaldo Carvalho de Melo static void dccp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, 88d5fdd6baSBrian Haley u8 type, u8 code, int offset, __be32 info) 893df80d93SArnaldo Carvalho de Melo { 903df80d93SArnaldo Carvalho de Melo struct ipv6hdr *hdr = (struct ipv6hdr *)skb->data; 913df80d93SArnaldo Carvalho de Melo const struct dccp_hdr *dh = (struct dccp_hdr *)(skb->data + offset); 92e0bcfb0cSWei Yongjun struct dccp_sock *dp; 933df80d93SArnaldo Carvalho de Melo struct ipv6_pinfo *np; 943df80d93SArnaldo Carvalho de Melo struct sock *sk; 953df80d93SArnaldo Carvalho de Melo int err; 963df80d93SArnaldo Carvalho de Melo __u64 seq; 97ca12a1a4SPavel Emelyanov struct net *net = dev_net(skb->dev); 983df80d93SArnaldo Carvalho de Melo 99860239c5SWei Yongjun if (skb->len < offset + sizeof(*dh) || 100860239c5SWei Yongjun skb->len < offset + __dccp_basic_hdr_len(dh)) { 101e41b5368SDenis V. Lunev ICMP6_INC_STATS_BH(net, __in6_dev_get(skb->dev), 102e41b5368SDenis V. Lunev ICMP6_MIB_INERRORS); 103860239c5SWei Yongjun return; 104860239c5SWei Yongjun } 105860239c5SWei Yongjun 106ca12a1a4SPavel Emelyanov sk = inet6_lookup(net, &dccp_hashinfo, 107671a1c74SPavel Emelyanov &hdr->daddr, dh->dccph_dport, 108f2776ff0SYOSHIFUJI Hideaki &hdr->saddr, dh->dccph_sport, inet6_iif(skb)); 1093df80d93SArnaldo Carvalho de Melo 1103df80d93SArnaldo Carvalho de Melo if (sk == NULL) { 111e41b5368SDenis V. Lunev ICMP6_INC_STATS_BH(net, __in6_dev_get(skb->dev), 112e41b5368SDenis V. Lunev ICMP6_MIB_INERRORS); 1133df80d93SArnaldo Carvalho de Melo return; 1143df80d93SArnaldo Carvalho de Melo } 1153df80d93SArnaldo Carvalho de Melo 1163df80d93SArnaldo Carvalho de Melo if (sk->sk_state == DCCP_TIME_WAIT) { 1179469c7b4SYOSHIFUJI Hideaki inet_twsk_put(inet_twsk(sk)); 1183df80d93SArnaldo Carvalho de Melo return; 1193df80d93SArnaldo Carvalho de Melo } 1203df80d93SArnaldo Carvalho de Melo 1213df80d93SArnaldo Carvalho de Melo bh_lock_sock(sk); 1223df80d93SArnaldo Carvalho de Melo if (sock_owned_by_user(sk)) 123de0744afSPavel Emelyanov NET_INC_STATS_BH(net, LINUX_MIB_LOCKDROPPEDICMPS); 1243df80d93SArnaldo Carvalho de Melo 1253df80d93SArnaldo Carvalho de Melo if (sk->sk_state == DCCP_CLOSED) 1263df80d93SArnaldo Carvalho de Melo goto out; 1273df80d93SArnaldo Carvalho de Melo 128e0bcfb0cSWei Yongjun dp = dccp_sk(sk); 129e0bcfb0cSWei Yongjun seq = dccp_hdr_seq(dh); 130e0bcfb0cSWei Yongjun if ((1 << sk->sk_state) & ~(DCCPF_REQUESTING | DCCPF_LISTEN) && 131e0bcfb0cSWei Yongjun !between48(seq, dp->dccps_awl, dp->dccps_awh)) { 132e0bcfb0cSWei Yongjun NET_INC_STATS_BH(net, LINUX_MIB_OUTOFWINDOWICMPS); 133e0bcfb0cSWei Yongjun goto out; 134e0bcfb0cSWei Yongjun } 135e0bcfb0cSWei Yongjun 1363df80d93SArnaldo Carvalho de Melo np = inet6_sk(sk); 1373df80d93SArnaldo Carvalho de Melo 1383df80d93SArnaldo Carvalho de Melo if (type == ICMPV6_PKT_TOOBIG) { 1393df80d93SArnaldo Carvalho de Melo struct dst_entry *dst = NULL; 1403df80d93SArnaldo Carvalho de Melo 1413df80d93SArnaldo Carvalho de Melo if (sock_owned_by_user(sk)) 1423df80d93SArnaldo Carvalho de Melo goto out; 1433df80d93SArnaldo Carvalho de Melo if ((1 << sk->sk_state) & (DCCPF_LISTEN | DCCPF_CLOSED)) 1443df80d93SArnaldo Carvalho de Melo goto out; 1453df80d93SArnaldo Carvalho de Melo 1463df80d93SArnaldo Carvalho de Melo /* icmp should have updated the destination cache entry */ 1473df80d93SArnaldo Carvalho de Melo dst = __sk_dst_check(sk, np->dst_cookie); 1483df80d93SArnaldo Carvalho de Melo if (dst == NULL) { 1493df80d93SArnaldo Carvalho de Melo struct inet_sock *inet = inet_sk(sk); 1503df80d93SArnaldo Carvalho de Melo struct flowi fl; 1513df80d93SArnaldo Carvalho de Melo 1523df80d93SArnaldo Carvalho de Melo /* BUGGG_FUTURE: Again, it is not clear how 1533df80d93SArnaldo Carvalho de Melo to handle rthdr case. Ignore this complexity 1543df80d93SArnaldo Carvalho de Melo for now. 1553df80d93SArnaldo Carvalho de Melo */ 1563df80d93SArnaldo Carvalho de Melo memset(&fl, 0, sizeof(fl)); 1573df80d93SArnaldo Carvalho de Melo fl.proto = IPPROTO_DCCP; 1583df80d93SArnaldo Carvalho de Melo ipv6_addr_copy(&fl.fl6_dst, &np->daddr); 1593df80d93SArnaldo Carvalho de Melo ipv6_addr_copy(&fl.fl6_src, &np->saddr); 1603df80d93SArnaldo Carvalho de Melo fl.oif = sk->sk_bound_dev_if; 161c720c7e8SEric Dumazet fl.fl_ip_dport = inet->inet_dport; 162c720c7e8SEric Dumazet fl.fl_ip_sport = inet->inet_sport; 163beb8d13bSVenkat Yekkirala security_sk_classify_flow(sk, &fl); 1643df80d93SArnaldo Carvalho de Melo 16545329e71SArnaldo Carvalho de Melo err = ip6_dst_lookup(sk, &dst, &fl); 16645329e71SArnaldo Carvalho de Melo if (err) { 1673df80d93SArnaldo Carvalho de Melo sk->sk_err_soft = -err; 1683df80d93SArnaldo Carvalho de Melo goto out; 1693df80d93SArnaldo Carvalho de Melo } 1703df80d93SArnaldo Carvalho de Melo 17152479b62SAlexey Dobriyan err = xfrm_lookup(net, &dst, &fl, sk, 0); 17245329e71SArnaldo Carvalho de Melo if (err < 0) { 1733df80d93SArnaldo Carvalho de Melo sk->sk_err_soft = -err; 1743df80d93SArnaldo Carvalho de Melo goto out; 1753df80d93SArnaldo Carvalho de Melo } 1763df80d93SArnaldo Carvalho de Melo } else 1773df80d93SArnaldo Carvalho de Melo dst_hold(dst); 1783df80d93SArnaldo Carvalho de Melo 179d83d8461SArnaldo Carvalho de Melo if (inet_csk(sk)->icsk_pmtu_cookie > dst_mtu(dst)) { 1803df80d93SArnaldo Carvalho de Melo dccp_sync_mss(sk, dst_mtu(dst)); 1813df80d93SArnaldo Carvalho de Melo } /* else let the usual retransmit timer handle it */ 1823df80d93SArnaldo Carvalho de Melo dst_release(dst); 1833df80d93SArnaldo Carvalho de Melo goto out; 1843df80d93SArnaldo Carvalho de Melo } 1853df80d93SArnaldo Carvalho de Melo 1863df80d93SArnaldo Carvalho de Melo icmpv6_err_convert(type, code, &err); 1873df80d93SArnaldo Carvalho de Melo 1883df80d93SArnaldo Carvalho de Melo /* Might be for an request_sock */ 1893df80d93SArnaldo Carvalho de Melo switch (sk->sk_state) { 1903df80d93SArnaldo Carvalho de Melo struct request_sock *req, **prev; 1913df80d93SArnaldo Carvalho de Melo case DCCP_LISTEN: 1923df80d93SArnaldo Carvalho de Melo if (sock_owned_by_user(sk)) 1933df80d93SArnaldo Carvalho de Melo goto out; 1943df80d93SArnaldo Carvalho de Melo 1953df80d93SArnaldo Carvalho de Melo req = inet6_csk_search_req(sk, &prev, dh->dccph_dport, 1963df80d93SArnaldo Carvalho de Melo &hdr->daddr, &hdr->saddr, 1973df80d93SArnaldo Carvalho de Melo inet6_iif(skb)); 19845329e71SArnaldo Carvalho de Melo if (req == NULL) 1993df80d93SArnaldo Carvalho de Melo goto out; 2003df80d93SArnaldo Carvalho de Melo 20145329e71SArnaldo Carvalho de Melo /* 20245329e71SArnaldo Carvalho de Melo * ICMPs are not backlogged, hence we cannot get an established 20345329e71SArnaldo Carvalho de Melo * socket here. 2043df80d93SArnaldo Carvalho de Melo */ 205547b792cSIlpo Järvinen WARN_ON(req->sk != NULL); 2063df80d93SArnaldo Carvalho de Melo 2073df80d93SArnaldo Carvalho de Melo if (seq != dccp_rsk(req)->dreq_iss) { 208de0744afSPavel Emelyanov NET_INC_STATS_BH(net, LINUX_MIB_OUTOFWINDOWICMPS); 2093df80d93SArnaldo Carvalho de Melo goto out; 2103df80d93SArnaldo Carvalho de Melo } 2113df80d93SArnaldo Carvalho de Melo 2123df80d93SArnaldo Carvalho de Melo inet_csk_reqsk_queue_drop(sk, req, prev); 2133df80d93SArnaldo Carvalho de Melo goto out; 2143df80d93SArnaldo Carvalho de Melo 2153df80d93SArnaldo Carvalho de Melo case DCCP_REQUESTING: 2163df80d93SArnaldo Carvalho de Melo case DCCP_RESPOND: /* Cannot happen. 2173df80d93SArnaldo Carvalho de Melo It can, it SYNs are crossed. --ANK */ 2183df80d93SArnaldo Carvalho de Melo if (!sock_owned_by_user(sk)) { 2193df80d93SArnaldo Carvalho de Melo DCCP_INC_STATS_BH(DCCP_MIB_ATTEMPTFAILS); 2203df80d93SArnaldo Carvalho de Melo sk->sk_err = err; 2213df80d93SArnaldo Carvalho de Melo /* 2223df80d93SArnaldo Carvalho de Melo * Wake people up to see the error 2233df80d93SArnaldo Carvalho de Melo * (see connect in sock.c) 2243df80d93SArnaldo Carvalho de Melo */ 2253df80d93SArnaldo Carvalho de Melo sk->sk_error_report(sk); 2263df80d93SArnaldo Carvalho de Melo dccp_done(sk); 2273df80d93SArnaldo Carvalho de Melo } else 2283df80d93SArnaldo Carvalho de Melo sk->sk_err_soft = err; 2293df80d93SArnaldo Carvalho de Melo goto out; 2303df80d93SArnaldo Carvalho de Melo } 2313df80d93SArnaldo Carvalho de Melo 2323df80d93SArnaldo Carvalho de Melo if (!sock_owned_by_user(sk) && np->recverr) { 2333df80d93SArnaldo Carvalho de Melo sk->sk_err = err; 2343df80d93SArnaldo Carvalho de Melo sk->sk_error_report(sk); 2353df80d93SArnaldo Carvalho de Melo } else 2363df80d93SArnaldo Carvalho de Melo sk->sk_err_soft = err; 2373df80d93SArnaldo Carvalho de Melo 2383df80d93SArnaldo Carvalho de Melo out: 2393df80d93SArnaldo Carvalho de Melo bh_unlock_sock(sk); 2403df80d93SArnaldo Carvalho de Melo sock_put(sk); 2413df80d93SArnaldo Carvalho de Melo } 2423df80d93SArnaldo Carvalho de Melo 2433df80d93SArnaldo Carvalho de Melo 244e6b4d113SWilliam Allen Simpson static int dccp_v6_send_response(struct sock *sk, struct request_sock *req, 245e6b4d113SWilliam Allen Simpson struct request_values *rv_unused) 2463df80d93SArnaldo Carvalho de Melo { 2473df80d93SArnaldo Carvalho de Melo struct inet6_request_sock *ireq6 = inet6_rsk(req); 2483df80d93SArnaldo Carvalho de Melo struct ipv6_pinfo *np = inet6_sk(sk); 2493df80d93SArnaldo Carvalho de Melo struct sk_buff *skb; 2503df80d93SArnaldo Carvalho de Melo struct ipv6_txoptions *opt = NULL; 25120c59de2SArnaud Ebalard struct in6_addr *final_p, final; 2523df80d93SArnaldo Carvalho de Melo struct flowi fl; 2533df80d93SArnaldo Carvalho de Melo int err = -1; 254fd80eb94SDenis V. Lunev struct dst_entry *dst; 2553df80d93SArnaldo Carvalho de Melo 2563df80d93SArnaldo Carvalho de Melo memset(&fl, 0, sizeof(fl)); 2573df80d93SArnaldo Carvalho de Melo fl.proto = IPPROTO_DCCP; 2583df80d93SArnaldo Carvalho de Melo ipv6_addr_copy(&fl.fl6_dst, &ireq6->rmt_addr); 2593df80d93SArnaldo Carvalho de Melo ipv6_addr_copy(&fl.fl6_src, &ireq6->loc_addr); 2603df80d93SArnaldo Carvalho de Melo fl.fl6_flowlabel = 0; 2613df80d93SArnaldo Carvalho de Melo fl.oif = ireq6->iif; 2623df80d93SArnaldo Carvalho de Melo fl.fl_ip_dport = inet_rsk(req)->rmt_port; 263944f7502SGerrit Renker fl.fl_ip_sport = inet_rsk(req)->loc_port; 2644237c75cSVenkat Yekkirala security_req_classify_flow(req, &fl); 2653df80d93SArnaldo Carvalho de Melo 2663df80d93SArnaldo Carvalho de Melo opt = np->opt; 2673df80d93SArnaldo Carvalho de Melo 26820c59de2SArnaud Ebalard final_p = fl6_update_dst(&fl, opt, &final); 2693df80d93SArnaldo Carvalho de Melo 2703df80d93SArnaldo Carvalho de Melo err = ip6_dst_lookup(sk, &dst, &fl); 2713df80d93SArnaldo Carvalho de Melo if (err) 2723df80d93SArnaldo Carvalho de Melo goto done; 27345329e71SArnaldo Carvalho de Melo 2743df80d93SArnaldo Carvalho de Melo if (final_p) 2753df80d93SArnaldo Carvalho de Melo ipv6_addr_copy(&fl.fl6_dst, final_p); 27645329e71SArnaldo Carvalho de Melo 27752479b62SAlexey Dobriyan err = xfrm_lookup(sock_net(sk), &dst, &fl, sk, 0); 27845329e71SArnaldo Carvalho de Melo if (err < 0) 2793df80d93SArnaldo Carvalho de Melo goto done; 2803df80d93SArnaldo Carvalho de Melo 2813df80d93SArnaldo Carvalho de Melo skb = dccp_make_response(sk, dst, req); 2823df80d93SArnaldo Carvalho de Melo if (skb != NULL) { 2833df80d93SArnaldo Carvalho de Melo struct dccp_hdr *dh = dccp_hdr(skb); 28445329e71SArnaldo Carvalho de Melo 2856f4e5fffSGerrit Renker dh->dccph_checksum = dccp_v6_csum_finish(skb, 2863df80d93SArnaldo Carvalho de Melo &ireq6->loc_addr, 2876f4e5fffSGerrit Renker &ireq6->rmt_addr); 2883df80d93SArnaldo Carvalho de Melo ipv6_addr_copy(&fl.fl6_dst, &ireq6->rmt_addr); 2894e15ed4dSShan Wei err = ip6_xmit(sk, skb, &fl, opt); 290b9df3cb8SGerrit Renker err = net_xmit_eval(err); 2913df80d93SArnaldo Carvalho de Melo } 2923df80d93SArnaldo Carvalho de Melo 2933df80d93SArnaldo Carvalho de Melo done: 29445329e71SArnaldo Carvalho de Melo if (opt != NULL && opt != np->opt) 2953df80d93SArnaldo Carvalho de Melo sock_kfree_s(sk, opt, opt->tot_len); 2960cbd7825SDavid S. Miller dst_release(dst); 2973df80d93SArnaldo Carvalho de Melo return err; 2983df80d93SArnaldo Carvalho de Melo } 2993df80d93SArnaldo Carvalho de Melo 3003df80d93SArnaldo Carvalho de Melo static void dccp_v6_reqsk_destructor(struct request_sock *req) 3013df80d93SArnaldo Carvalho de Melo { 302d99a7bd2SGerrit Renker dccp_feat_list_purge(&dccp_rsk(req)->dreq_featneg); 3033df80d93SArnaldo Carvalho de Melo if (inet6_rsk(req)->pktopts != NULL) 3043df80d93SArnaldo Carvalho de Melo kfree_skb(inet6_rsk(req)->pktopts); 3053df80d93SArnaldo Carvalho de Melo } 3063df80d93SArnaldo Carvalho de Melo 307cfb6eeb4SYOSHIFUJI Hideaki static void dccp_v6_ctl_send_reset(struct sock *sk, struct sk_buff *rxskb) 3083df80d93SArnaldo Carvalho de Melo { 3090660e03fSArnaldo Carvalho de Melo struct ipv6hdr *rxip6h; 3103df80d93SArnaldo Carvalho de Melo struct sk_buff *skb; 3113df80d93SArnaldo Carvalho de Melo struct flowi fl; 312adf30907SEric Dumazet struct net *net = dev_net(skb_dst(rxskb)->dev); 313334527d3SPavel Emelyanov struct sock *ctl_sk = net->dccp.v6_ctl_sk; 314adf30907SEric Dumazet struct dst_entry *dst; 3153df80d93SArnaldo Carvalho de Melo 316e356d37aSGerrit Renker if (dccp_hdr(rxskb)->dccph_type == DCCP_PKT_RESET) 3173df80d93SArnaldo Carvalho de Melo return; 3183df80d93SArnaldo Carvalho de Melo 3193df80d93SArnaldo Carvalho de Melo if (!ipv6_unicast_destination(rxskb)) 3203df80d93SArnaldo Carvalho de Melo return; 3213df80d93SArnaldo Carvalho de Melo 32202047741SPavel Emelyanov skb = dccp_ctl_make_reset(ctl_sk, rxskb); 3233df80d93SArnaldo Carvalho de Melo if (skb == NULL) 3243df80d93SArnaldo Carvalho de Melo return; 3253df80d93SArnaldo Carvalho de Melo 3260660e03fSArnaldo Carvalho de Melo rxip6h = ipv6_hdr(rxskb); 327e356d37aSGerrit Renker dccp_hdr(skb)->dccph_checksum = dccp_v6_csum_finish(skb, &rxip6h->saddr, 3280660e03fSArnaldo Carvalho de Melo &rxip6h->daddr); 3296f4e5fffSGerrit Renker 3303df80d93SArnaldo Carvalho de Melo memset(&fl, 0, sizeof(fl)); 3310660e03fSArnaldo Carvalho de Melo ipv6_addr_copy(&fl.fl6_dst, &rxip6h->saddr); 3320660e03fSArnaldo Carvalho de Melo ipv6_addr_copy(&fl.fl6_src, &rxip6h->daddr); 3336f4e5fffSGerrit Renker 3343df80d93SArnaldo Carvalho de Melo fl.proto = IPPROTO_DCCP; 3353df80d93SArnaldo Carvalho de Melo fl.oif = inet6_iif(rxskb); 336e356d37aSGerrit Renker fl.fl_ip_dport = dccp_hdr(skb)->dccph_dport; 337e356d37aSGerrit Renker fl.fl_ip_sport = dccp_hdr(skb)->dccph_sport; 338beb8d13bSVenkat Yekkirala security_skb_classify_flow(rxskb, &fl); 3393df80d93SArnaldo Carvalho de Melo 3403df80d93SArnaldo Carvalho de Melo /* sk = NULL, but it is safe for now. RST socket required. */ 341adf30907SEric Dumazet if (!ip6_dst_lookup(ctl_sk, &dst, &fl)) { 342adf30907SEric Dumazet if (xfrm_lookup(net, &dst, &fl, NULL, 0) >= 0) { 343adf30907SEric Dumazet skb_dst_set(skb, dst); 3444e15ed4dSShan Wei ip6_xmit(ctl_sk, skb, &fl, NULL); 3453df80d93SArnaldo Carvalho de Melo DCCP_INC_STATS_BH(DCCP_MIB_OUTSEGS); 3463df80d93SArnaldo Carvalho de Melo DCCP_INC_STATS_BH(DCCP_MIB_OUTRSTS); 3473df80d93SArnaldo Carvalho de Melo return; 3483df80d93SArnaldo Carvalho de Melo } 3493df80d93SArnaldo Carvalho de Melo } 3503df80d93SArnaldo Carvalho de Melo 3513df80d93SArnaldo Carvalho de Melo kfree_skb(skb); 3523df80d93SArnaldo Carvalho de Melo } 3533df80d93SArnaldo Carvalho de Melo 35473c9e02cSGerrit Renker static struct request_sock_ops dccp6_request_sock_ops = { 35573c9e02cSGerrit Renker .family = AF_INET6, 35673c9e02cSGerrit Renker .obj_size = sizeof(struct dccp6_request_sock), 35773c9e02cSGerrit Renker .rtx_syn_ack = dccp_v6_send_response, 35873c9e02cSGerrit Renker .send_ack = dccp_reqsk_send_ack, 35973c9e02cSGerrit Renker .destructor = dccp_v6_reqsk_destructor, 36073c9e02cSGerrit Renker .send_reset = dccp_v6_ctl_send_reset, 36173c9e02cSGerrit Renker }; 36273c9e02cSGerrit Renker 3633df80d93SArnaldo Carvalho de Melo static struct sock *dccp_v6_hnd_req(struct sock *sk,struct sk_buff *skb) 3643df80d93SArnaldo Carvalho de Melo { 3653df80d93SArnaldo Carvalho de Melo const struct dccp_hdr *dh = dccp_hdr(skb); 3660660e03fSArnaldo Carvalho de Melo const struct ipv6hdr *iph = ipv6_hdr(skb); 3673df80d93SArnaldo Carvalho de Melo struct sock *nsk; 3683df80d93SArnaldo Carvalho de Melo struct request_sock **prev; 3693df80d93SArnaldo Carvalho de Melo /* Find possible connection requests. */ 3703df80d93SArnaldo Carvalho de Melo struct request_sock *req = inet6_csk_search_req(sk, &prev, 3713df80d93SArnaldo Carvalho de Melo dh->dccph_sport, 3723df80d93SArnaldo Carvalho de Melo &iph->saddr, 3733df80d93SArnaldo Carvalho de Melo &iph->daddr, 3743df80d93SArnaldo Carvalho de Melo inet6_iif(skb)); 3753df80d93SArnaldo Carvalho de Melo if (req != NULL) 3763df80d93SArnaldo Carvalho de Melo return dccp_check_req(sk, skb, req, prev); 3773df80d93SArnaldo Carvalho de Melo 378671a1c74SPavel Emelyanov nsk = __inet6_lookup_established(sock_net(sk), &dccp_hashinfo, 3793df80d93SArnaldo Carvalho de Melo &iph->saddr, dh->dccph_sport, 3803df80d93SArnaldo Carvalho de Melo &iph->daddr, ntohs(dh->dccph_dport), 3813df80d93SArnaldo Carvalho de Melo inet6_iif(skb)); 3823df80d93SArnaldo Carvalho de Melo if (nsk != NULL) { 3833df80d93SArnaldo Carvalho de Melo if (nsk->sk_state != DCCP_TIME_WAIT) { 3843df80d93SArnaldo Carvalho de Melo bh_lock_sock(nsk); 3853df80d93SArnaldo Carvalho de Melo return nsk; 3863df80d93SArnaldo Carvalho de Melo } 3879469c7b4SYOSHIFUJI Hideaki inet_twsk_put(inet_twsk(nsk)); 3883df80d93SArnaldo Carvalho de Melo return NULL; 3893df80d93SArnaldo Carvalho de Melo } 3903df80d93SArnaldo Carvalho de Melo 3913df80d93SArnaldo Carvalho de Melo return sk; 3923df80d93SArnaldo Carvalho de Melo } 3933df80d93SArnaldo Carvalho de Melo 3943df80d93SArnaldo Carvalho de Melo static int dccp_v6_conn_request(struct sock *sk, struct sk_buff *skb) 3953df80d93SArnaldo Carvalho de Melo { 3963df80d93SArnaldo Carvalho de Melo struct request_sock *req; 3973df80d93SArnaldo Carvalho de Melo struct dccp_request_sock *dreq; 3983df80d93SArnaldo Carvalho de Melo struct inet6_request_sock *ireq6; 3993df80d93SArnaldo Carvalho de Melo struct ipv6_pinfo *np = inet6_sk(sk); 40060fe62e7SAndrea Bittau const __be32 service = dccp_hdr_request(skb)->dccph_req_service; 4013df80d93SArnaldo Carvalho de Melo struct dccp_skb_cb *dcb = DCCP_SKB_CB(skb); 4023df80d93SArnaldo Carvalho de Melo 4033df80d93SArnaldo Carvalho de Melo if (skb->protocol == htons(ETH_P_IP)) 4043df80d93SArnaldo Carvalho de Melo return dccp_v4_conn_request(sk, skb); 4053df80d93SArnaldo Carvalho de Melo 4063df80d93SArnaldo Carvalho de Melo if (!ipv6_unicast_destination(skb)) 4074a5409a5SGerrit Renker return 0; /* discard, don't send a reset here */ 4083df80d93SArnaldo Carvalho de Melo 4093df80d93SArnaldo Carvalho de Melo if (dccp_bad_service_code(sk, service)) { 4104a5409a5SGerrit Renker dcb->dccpd_reset_code = DCCP_RESET_CODE_BAD_SERVICE_CODE; 4113df80d93SArnaldo Carvalho de Melo goto drop; 4123df80d93SArnaldo Carvalho de Melo } 4133df80d93SArnaldo Carvalho de Melo /* 4143df80d93SArnaldo Carvalho de Melo * There are no SYN attacks on IPv6, yet... 4153df80d93SArnaldo Carvalho de Melo */ 4164a5409a5SGerrit Renker dcb->dccpd_reset_code = DCCP_RESET_CODE_TOO_BUSY; 4173df80d93SArnaldo Carvalho de Melo if (inet_csk_reqsk_queue_is_full(sk)) 4183df80d93SArnaldo Carvalho de Melo goto drop; 4193df80d93SArnaldo Carvalho de Melo 4203df80d93SArnaldo Carvalho de Melo if (sk_acceptq_is_full(sk) && inet_csk_reqsk_queue_young(sk) > 1) 4213df80d93SArnaldo Carvalho de Melo goto drop; 4223df80d93SArnaldo Carvalho de Melo 42382709531SGerrit Renker req = inet6_reqsk_alloc(&dccp6_request_sock_ops); 4243df80d93SArnaldo Carvalho de Melo if (req == NULL) 4253df80d93SArnaldo Carvalho de Melo goto drop; 4263df80d93SArnaldo Carvalho de Melo 427ac75773cSGerrit Renker if (dccp_reqsk_init(req, dccp_sk(sk), skb)) 428ac75773cSGerrit Renker goto drop_and_free; 4293df80d93SArnaldo Carvalho de Melo 4308b819412SGerrit Renker dreq = dccp_rsk(req); 4318b819412SGerrit Renker if (dccp_parse_options(sk, dreq, skb)) 4328b819412SGerrit Renker goto drop_and_free; 4338b819412SGerrit Renker 4344237c75cSVenkat Yekkirala if (security_inet_conn_request(sk, skb, req)) 4354237c75cSVenkat Yekkirala goto drop_and_free; 4364237c75cSVenkat Yekkirala 4373df80d93SArnaldo Carvalho de Melo ireq6 = inet6_rsk(req); 4380660e03fSArnaldo Carvalho de Melo ipv6_addr_copy(&ireq6->rmt_addr, &ipv6_hdr(skb)->saddr); 4390660e03fSArnaldo Carvalho de Melo ipv6_addr_copy(&ireq6->loc_addr, &ipv6_hdr(skb)->daddr); 4403df80d93SArnaldo Carvalho de Melo 4413df80d93SArnaldo Carvalho de Melo if (ipv6_opt_accepted(sk, skb) || 4423df80d93SArnaldo Carvalho de Melo np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo || 4433df80d93SArnaldo Carvalho de Melo np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim) { 4443df80d93SArnaldo Carvalho de Melo atomic_inc(&skb->users); 4453df80d93SArnaldo Carvalho de Melo ireq6->pktopts = skb; 4463df80d93SArnaldo Carvalho de Melo } 4473df80d93SArnaldo Carvalho de Melo ireq6->iif = sk->sk_bound_dev_if; 4483df80d93SArnaldo Carvalho de Melo 4493df80d93SArnaldo Carvalho de Melo /* So that link locals have meaning */ 4503df80d93SArnaldo Carvalho de Melo if (!sk->sk_bound_dev_if && 4513df80d93SArnaldo Carvalho de Melo ipv6_addr_type(&ireq6->rmt_addr) & IPV6_ADDR_LINKLOCAL) 4523df80d93SArnaldo Carvalho de Melo ireq6->iif = inet6_iif(skb); 4533df80d93SArnaldo Carvalho de Melo 4543df80d93SArnaldo Carvalho de Melo /* 4553df80d93SArnaldo Carvalho de Melo * Step 3: Process LISTEN state 4563df80d93SArnaldo Carvalho de Melo * 4573df80d93SArnaldo Carvalho de Melo * Set S.ISR, S.GSR, S.SWL, S.SWH from packet or Init Cookie 4583df80d93SArnaldo Carvalho de Melo * 4593df80d93SArnaldo Carvalho de Melo * In fact we defer setting S.GSR, S.SWL, S.SWH to 4603df80d93SArnaldo Carvalho de Melo * dccp_create_openreq_child. 4613df80d93SArnaldo Carvalho de Melo */ 4623df80d93SArnaldo Carvalho de Melo dreq->dreq_isr = dcb->dccpd_seq; 463865e9022SGerrit Renker dreq->dreq_iss = dccp_v6_init_sequence(skb); 4643df80d93SArnaldo Carvalho de Melo dreq->dreq_service = service; 4653df80d93SArnaldo Carvalho de Melo 466e6b4d113SWilliam Allen Simpson if (dccp_v6_send_response(sk, req, NULL)) 4673df80d93SArnaldo Carvalho de Melo goto drop_and_free; 4683df80d93SArnaldo Carvalho de Melo 4693df80d93SArnaldo Carvalho de Melo inet6_csk_reqsk_queue_hash_add(sk, req, DCCP_TIMEOUT_INIT); 4703df80d93SArnaldo Carvalho de Melo return 0; 4713df80d93SArnaldo Carvalho de Melo 4723df80d93SArnaldo Carvalho de Melo drop_and_free: 4733df80d93SArnaldo Carvalho de Melo reqsk_free(req); 4743df80d93SArnaldo Carvalho de Melo drop: 4753df80d93SArnaldo Carvalho de Melo DCCP_INC_STATS_BH(DCCP_MIB_ATTEMPTFAILS); 4763df80d93SArnaldo Carvalho de Melo return -1; 4773df80d93SArnaldo Carvalho de Melo } 4783df80d93SArnaldo Carvalho de Melo 4793df80d93SArnaldo Carvalho de Melo static struct sock *dccp_v6_request_recv_sock(struct sock *sk, 4803df80d93SArnaldo Carvalho de Melo struct sk_buff *skb, 4813df80d93SArnaldo Carvalho de Melo struct request_sock *req, 4823df80d93SArnaldo Carvalho de Melo struct dst_entry *dst) 4833df80d93SArnaldo Carvalho de Melo { 4843df80d93SArnaldo Carvalho de Melo struct inet6_request_sock *ireq6 = inet6_rsk(req); 4853df80d93SArnaldo Carvalho de Melo struct ipv6_pinfo *newnp, *np = inet6_sk(sk); 4863df80d93SArnaldo Carvalho de Melo struct inet_sock *newinet; 4873df80d93SArnaldo Carvalho de Melo struct dccp_sock *newdp; 4883df80d93SArnaldo Carvalho de Melo struct dccp6_sock *newdp6; 4893df80d93SArnaldo Carvalho de Melo struct sock *newsk; 4903df80d93SArnaldo Carvalho de Melo struct ipv6_txoptions *opt; 4913df80d93SArnaldo Carvalho de Melo 4923df80d93SArnaldo Carvalho de Melo if (skb->protocol == htons(ETH_P_IP)) { 4933df80d93SArnaldo Carvalho de Melo /* 4943df80d93SArnaldo Carvalho de Melo * v6 mapped 4953df80d93SArnaldo Carvalho de Melo */ 4963df80d93SArnaldo Carvalho de Melo newsk = dccp_v4_request_recv_sock(sk, skb, req, dst); 4973df80d93SArnaldo Carvalho de Melo if (newsk == NULL) 4983df80d93SArnaldo Carvalho de Melo return NULL; 4993df80d93SArnaldo Carvalho de Melo 5003df80d93SArnaldo Carvalho de Melo newdp6 = (struct dccp6_sock *)newsk; 5013df80d93SArnaldo Carvalho de Melo newdp = dccp_sk(newsk); 5023df80d93SArnaldo Carvalho de Melo newinet = inet_sk(newsk); 5033df80d93SArnaldo Carvalho de Melo newinet->pinet6 = &newdp6->inet6; 5043df80d93SArnaldo Carvalho de Melo newnp = inet6_sk(newsk); 5053df80d93SArnaldo Carvalho de Melo 5063df80d93SArnaldo Carvalho de Melo memcpy(newnp, np, sizeof(struct ipv6_pinfo)); 5073df80d93SArnaldo Carvalho de Melo 508c720c7e8SEric Dumazet ipv6_addr_set_v4mapped(newinet->inet_daddr, &newnp->daddr); 5093df80d93SArnaldo Carvalho de Melo 510c720c7e8SEric Dumazet ipv6_addr_set_v4mapped(newinet->inet_saddr, &newnp->saddr); 5113df80d93SArnaldo Carvalho de Melo 5123df80d93SArnaldo Carvalho de Melo ipv6_addr_copy(&newnp->rcv_saddr, &newnp->saddr); 5133df80d93SArnaldo Carvalho de Melo 5143df80d93SArnaldo Carvalho de Melo inet_csk(newsk)->icsk_af_ops = &dccp_ipv6_mapped; 5153df80d93SArnaldo Carvalho de Melo newsk->sk_backlog_rcv = dccp_v4_do_rcv; 5163df80d93SArnaldo Carvalho de Melo newnp->pktoptions = NULL; 5173df80d93SArnaldo Carvalho de Melo newnp->opt = NULL; 5183df80d93SArnaldo Carvalho de Melo newnp->mcast_oif = inet6_iif(skb); 5190660e03fSArnaldo Carvalho de Melo newnp->mcast_hops = ipv6_hdr(skb)->hop_limit; 5203df80d93SArnaldo Carvalho de Melo 5213df80d93SArnaldo Carvalho de Melo /* 5223df80d93SArnaldo Carvalho de Melo * No need to charge this sock to the relevant IPv6 refcnt debug socks count 5233df80d93SArnaldo Carvalho de Melo * here, dccp_create_openreq_child now does this for us, see the comment in 5243df80d93SArnaldo Carvalho de Melo * that function for the gory details. -acme 5253df80d93SArnaldo Carvalho de Melo */ 5263df80d93SArnaldo Carvalho de Melo 5273df80d93SArnaldo Carvalho de Melo /* It is tricky place. Until this moment IPv4 tcp 5283df80d93SArnaldo Carvalho de Melo worked with IPv6 icsk.icsk_af_ops. 5293df80d93SArnaldo Carvalho de Melo Sync it now. 5303df80d93SArnaldo Carvalho de Melo */ 531d83d8461SArnaldo Carvalho de Melo dccp_sync_mss(newsk, inet_csk(newsk)->icsk_pmtu_cookie); 5323df80d93SArnaldo Carvalho de Melo 5333df80d93SArnaldo Carvalho de Melo return newsk; 5343df80d93SArnaldo Carvalho de Melo } 5353df80d93SArnaldo Carvalho de Melo 5363df80d93SArnaldo Carvalho de Melo opt = np->opt; 5373df80d93SArnaldo Carvalho de Melo 5383df80d93SArnaldo Carvalho de Melo if (sk_acceptq_is_full(sk)) 5393df80d93SArnaldo Carvalho de Melo goto out_overflow; 5403df80d93SArnaldo Carvalho de Melo 5413df80d93SArnaldo Carvalho de Melo if (dst == NULL) { 54220c59de2SArnaud Ebalard struct in6_addr *final_p, final; 5433df80d93SArnaldo Carvalho de Melo struct flowi fl; 5443df80d93SArnaldo Carvalho de Melo 5453df80d93SArnaldo Carvalho de Melo memset(&fl, 0, sizeof(fl)); 5463df80d93SArnaldo Carvalho de Melo fl.proto = IPPROTO_DCCP; 5473df80d93SArnaldo Carvalho de Melo ipv6_addr_copy(&fl.fl6_dst, &ireq6->rmt_addr); 54820c59de2SArnaud Ebalard final_p = fl6_update_dst(&fl, opt, &final); 5493df80d93SArnaldo Carvalho de Melo ipv6_addr_copy(&fl.fl6_src, &ireq6->loc_addr); 5503df80d93SArnaldo Carvalho de Melo fl.oif = sk->sk_bound_dev_if; 5513df80d93SArnaldo Carvalho de Melo fl.fl_ip_dport = inet_rsk(req)->rmt_port; 552944f7502SGerrit Renker fl.fl_ip_sport = inet_rsk(req)->loc_port; 553beb8d13bSVenkat Yekkirala security_sk_classify_flow(sk, &fl); 5543df80d93SArnaldo Carvalho de Melo 5553df80d93SArnaldo Carvalho de Melo if (ip6_dst_lookup(sk, &dst, &fl)) 5563df80d93SArnaldo Carvalho de Melo goto out; 5573df80d93SArnaldo Carvalho de Melo 5583df80d93SArnaldo Carvalho de Melo if (final_p) 5593df80d93SArnaldo Carvalho de Melo ipv6_addr_copy(&fl.fl6_dst, final_p); 5603df80d93SArnaldo Carvalho de Melo 56152479b62SAlexey Dobriyan if ((xfrm_lookup(sock_net(sk), &dst, &fl, sk, 0)) < 0) 5623df80d93SArnaldo Carvalho de Melo goto out; 5633df80d93SArnaldo Carvalho de Melo } 5643df80d93SArnaldo Carvalho de Melo 5653df80d93SArnaldo Carvalho de Melo newsk = dccp_create_openreq_child(sk, req, skb); 5663df80d93SArnaldo Carvalho de Melo if (newsk == NULL) 567*093d2823SBalazs Scheidler goto out_nonewsk; 5683df80d93SArnaldo Carvalho de Melo 5693df80d93SArnaldo Carvalho de Melo /* 5703df80d93SArnaldo Carvalho de Melo * No need to charge this sock to the relevant IPv6 refcnt debug socks 5713df80d93SArnaldo Carvalho de Melo * count here, dccp_create_openreq_child now does this for us, see the 5723df80d93SArnaldo Carvalho de Melo * comment in that function for the gory details. -acme 5733df80d93SArnaldo Carvalho de Melo */ 5743df80d93SArnaldo Carvalho de Melo 5758e1ef0a9SYOSHIFUJI Hideaki __ip6_dst_store(newsk, dst, NULL, NULL); 57645329e71SArnaldo Carvalho de Melo newsk->sk_route_caps = dst->dev->features & ~(NETIF_F_IP_CSUM | 57745329e71SArnaldo Carvalho de Melo NETIF_F_TSO); 5783df80d93SArnaldo Carvalho de Melo newdp6 = (struct dccp6_sock *)newsk; 5793df80d93SArnaldo Carvalho de Melo newinet = inet_sk(newsk); 5803df80d93SArnaldo Carvalho de Melo newinet->pinet6 = &newdp6->inet6; 5813df80d93SArnaldo Carvalho de Melo newdp = dccp_sk(newsk); 5823df80d93SArnaldo Carvalho de Melo newnp = inet6_sk(newsk); 5833df80d93SArnaldo Carvalho de Melo 5843df80d93SArnaldo Carvalho de Melo memcpy(newnp, np, sizeof(struct ipv6_pinfo)); 5853df80d93SArnaldo Carvalho de Melo 5863df80d93SArnaldo Carvalho de Melo ipv6_addr_copy(&newnp->daddr, &ireq6->rmt_addr); 5873df80d93SArnaldo Carvalho de Melo ipv6_addr_copy(&newnp->saddr, &ireq6->loc_addr); 5883df80d93SArnaldo Carvalho de Melo ipv6_addr_copy(&newnp->rcv_saddr, &ireq6->loc_addr); 5893df80d93SArnaldo Carvalho de Melo newsk->sk_bound_dev_if = ireq6->iif; 5903df80d93SArnaldo Carvalho de Melo 5913df80d93SArnaldo Carvalho de Melo /* Now IPv6 options... 5923df80d93SArnaldo Carvalho de Melo 5933df80d93SArnaldo Carvalho de Melo First: no IPv4 options. 5943df80d93SArnaldo Carvalho de Melo */ 5953df80d93SArnaldo Carvalho de Melo newinet->opt = NULL; 5963df80d93SArnaldo Carvalho de Melo 5973df80d93SArnaldo Carvalho de Melo /* Clone RX bits */ 5983df80d93SArnaldo Carvalho de Melo newnp->rxopt.all = np->rxopt.all; 5993df80d93SArnaldo Carvalho de Melo 6003df80d93SArnaldo Carvalho de Melo /* Clone pktoptions received with SYN */ 6013df80d93SArnaldo Carvalho de Melo newnp->pktoptions = NULL; 6023df80d93SArnaldo Carvalho de Melo if (ireq6->pktopts != NULL) { 6033df80d93SArnaldo Carvalho de Melo newnp->pktoptions = skb_clone(ireq6->pktopts, GFP_ATOMIC); 6043df80d93SArnaldo Carvalho de Melo kfree_skb(ireq6->pktopts); 6053df80d93SArnaldo Carvalho de Melo ireq6->pktopts = NULL; 6063df80d93SArnaldo Carvalho de Melo if (newnp->pktoptions) 6073df80d93SArnaldo Carvalho de Melo skb_set_owner_r(newnp->pktoptions, newsk); 6083df80d93SArnaldo Carvalho de Melo } 6093df80d93SArnaldo Carvalho de Melo newnp->opt = NULL; 6103df80d93SArnaldo Carvalho de Melo newnp->mcast_oif = inet6_iif(skb); 6110660e03fSArnaldo Carvalho de Melo newnp->mcast_hops = ipv6_hdr(skb)->hop_limit; 6123df80d93SArnaldo Carvalho de Melo 61345329e71SArnaldo Carvalho de Melo /* 61445329e71SArnaldo Carvalho de Melo * Clone native IPv6 options from listening socket (if any) 61545329e71SArnaldo Carvalho de Melo * 61645329e71SArnaldo Carvalho de Melo * Yes, keeping reference count would be much more clever, but we make 61745329e71SArnaldo Carvalho de Melo * one more one thing there: reattach optmem to newsk. 6183df80d93SArnaldo Carvalho de Melo */ 61945329e71SArnaldo Carvalho de Melo if (opt != NULL) { 6203df80d93SArnaldo Carvalho de Melo newnp->opt = ipv6_dup_options(newsk, opt); 6213df80d93SArnaldo Carvalho de Melo if (opt != np->opt) 6223df80d93SArnaldo Carvalho de Melo sock_kfree_s(sk, opt, opt->tot_len); 6233df80d93SArnaldo Carvalho de Melo } 6243df80d93SArnaldo Carvalho de Melo 625d83d8461SArnaldo Carvalho de Melo inet_csk(newsk)->icsk_ext_hdr_len = 0; 62645329e71SArnaldo Carvalho de Melo if (newnp->opt != NULL) 627d83d8461SArnaldo Carvalho de Melo inet_csk(newsk)->icsk_ext_hdr_len = (newnp->opt->opt_nflen + 628d83d8461SArnaldo Carvalho de Melo newnp->opt->opt_flen); 6293df80d93SArnaldo Carvalho de Melo 6303df80d93SArnaldo Carvalho de Melo dccp_sync_mss(newsk, dst_mtu(dst)); 6313df80d93SArnaldo Carvalho de Melo 632c720c7e8SEric Dumazet newinet->inet_daddr = newinet->inet_saddr = LOOPBACK4_IPV6; 633c720c7e8SEric Dumazet newinet->inet_rcv_saddr = LOOPBACK4_IPV6; 6343df80d93SArnaldo Carvalho de Melo 635*093d2823SBalazs Scheidler if (__inet_inherit_port(sk, newsk) < 0) { 636*093d2823SBalazs Scheidler sock_put(newsk); 637*093d2823SBalazs Scheidler goto out; 638*093d2823SBalazs Scheidler } 6399327f705SEric Dumazet __inet6_hash(newsk, NULL); 6403df80d93SArnaldo Carvalho de Melo 6413df80d93SArnaldo Carvalho de Melo return newsk; 6423df80d93SArnaldo Carvalho de Melo 6433df80d93SArnaldo Carvalho de Melo out_overflow: 644de0744afSPavel Emelyanov NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENOVERFLOWS); 645*093d2823SBalazs Scheidler out_nonewsk: 646*093d2823SBalazs Scheidler dst_release(dst); 6473df80d93SArnaldo Carvalho de Melo out: 648de0744afSPavel Emelyanov NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENDROPS); 64945329e71SArnaldo Carvalho de Melo if (opt != NULL && opt != np->opt) 6503df80d93SArnaldo Carvalho de Melo sock_kfree_s(sk, opt, opt->tot_len); 6513df80d93SArnaldo Carvalho de Melo return NULL; 6523df80d93SArnaldo Carvalho de Melo } 6533df80d93SArnaldo Carvalho de Melo 6543df80d93SArnaldo Carvalho de Melo /* The socket must have it's spinlock held when we get 6553df80d93SArnaldo Carvalho de Melo * here. 6563df80d93SArnaldo Carvalho de Melo * 6573df80d93SArnaldo Carvalho de Melo * We have a potential double-lock case here, so even when 6583df80d93SArnaldo Carvalho de Melo * doing backlog processing we use the BH locking scheme. 6593df80d93SArnaldo Carvalho de Melo * This is because we cannot sleep with the original spinlock 6603df80d93SArnaldo Carvalho de Melo * held. 6613df80d93SArnaldo Carvalho de Melo */ 6623df80d93SArnaldo Carvalho de Melo static int dccp_v6_do_rcv(struct sock *sk, struct sk_buff *skb) 6633df80d93SArnaldo Carvalho de Melo { 6643df80d93SArnaldo Carvalho de Melo struct ipv6_pinfo *np = inet6_sk(sk); 6653df80d93SArnaldo Carvalho de Melo struct sk_buff *opt_skb = NULL; 6663df80d93SArnaldo Carvalho de Melo 6673df80d93SArnaldo Carvalho de Melo /* Imagine: socket is IPv6. IPv4 packet arrives, 6683df80d93SArnaldo Carvalho de Melo goes to IPv4 receive handler and backlogged. 6693df80d93SArnaldo Carvalho de Melo From backlog it always goes here. Kerboom... 6703df80d93SArnaldo Carvalho de Melo Fortunately, dccp_rcv_established and rcv_established 6713df80d93SArnaldo Carvalho de Melo handle them correctly, but it is not case with 6723df80d93SArnaldo Carvalho de Melo dccp_v6_hnd_req and dccp_v6_ctl_send_reset(). --ANK 6733df80d93SArnaldo Carvalho de Melo */ 6743df80d93SArnaldo Carvalho de Melo 6753df80d93SArnaldo Carvalho de Melo if (skb->protocol == htons(ETH_P_IP)) 6763df80d93SArnaldo Carvalho de Melo return dccp_v4_do_rcv(sk, skb); 6773df80d93SArnaldo Carvalho de Melo 678fda9ef5dSDmitry Mishin if (sk_filter(sk, skb)) 6793df80d93SArnaldo Carvalho de Melo goto discard; 6803df80d93SArnaldo Carvalho de Melo 6813df80d93SArnaldo Carvalho de Melo /* 68245329e71SArnaldo Carvalho de Melo * socket locking is here for SMP purposes as backlog rcv is currently 68345329e71SArnaldo Carvalho de Melo * called with bh processing disabled. 6843df80d93SArnaldo Carvalho de Melo */ 6853df80d93SArnaldo Carvalho de Melo 6863df80d93SArnaldo Carvalho de Melo /* Do Stevens' IPV6_PKTOPTIONS. 6873df80d93SArnaldo Carvalho de Melo 6883df80d93SArnaldo Carvalho de Melo Yes, guys, it is the only place in our code, where we 6893df80d93SArnaldo Carvalho de Melo may make it not affecting IPv4. 6903df80d93SArnaldo Carvalho de Melo The rest of code is protocol independent, 6913df80d93SArnaldo Carvalho de Melo and I do not like idea to uglify IPv4. 6923df80d93SArnaldo Carvalho de Melo 6933df80d93SArnaldo Carvalho de Melo Actually, all the idea behind IPV6_PKTOPTIONS 6943df80d93SArnaldo Carvalho de Melo looks not very well thought. For now we latch 6953df80d93SArnaldo Carvalho de Melo options, received in the last packet, enqueued 6963df80d93SArnaldo Carvalho de Melo by tcp. Feel free to propose better solution. 6973df80d93SArnaldo Carvalho de Melo --ANK (980728) 6983df80d93SArnaldo Carvalho de Melo */ 6993df80d93SArnaldo Carvalho de Melo if (np->rxopt.all) 70089e7e577SGerrit Renker /* 70189e7e577SGerrit Renker * FIXME: Add handling of IPV6_PKTOPTIONS skb. See the comments below 70289e7e577SGerrit Renker * (wrt ipv6_pktopions) and net/ipv6/tcp_ipv6.c for an example. 70389e7e577SGerrit Renker */ 7043df80d93SArnaldo Carvalho de Melo opt_skb = skb_clone(skb, GFP_ATOMIC); 7053df80d93SArnaldo Carvalho de Melo 7063df80d93SArnaldo Carvalho de Melo if (sk->sk_state == DCCP_OPEN) { /* Fast path */ 7073df80d93SArnaldo Carvalho de Melo if (dccp_rcv_established(sk, skb, dccp_hdr(skb), skb->len)) 7083df80d93SArnaldo Carvalho de Melo goto reset; 709fd169f15SDavid S. Miller if (opt_skb) { 71089e7e577SGerrit Renker /* XXX This is where we would goto ipv6_pktoptions. */ 711fd169f15SDavid S. Miller __kfree_skb(opt_skb); 712fd169f15SDavid S. Miller } 7133df80d93SArnaldo Carvalho de Melo return 0; 7143df80d93SArnaldo Carvalho de Melo } 7153df80d93SArnaldo Carvalho de Melo 716d83ca5acSGerrit Renker /* 717d83ca5acSGerrit Renker * Step 3: Process LISTEN state 718d83ca5acSGerrit Renker * If S.state == LISTEN, 719d83ca5acSGerrit Renker * If P.type == Request or P contains a valid Init Cookie option, 720d83ca5acSGerrit Renker * (* Must scan the packet's options to check for Init 721d83ca5acSGerrit Renker * Cookies. Only Init Cookies are processed here, 722d83ca5acSGerrit Renker * however; other options are processed in Step 8. This 723d83ca5acSGerrit Renker * scan need only be performed if the endpoint uses Init 724d83ca5acSGerrit Renker * Cookies *) 725d83ca5acSGerrit Renker * (* Generate a new socket and switch to that socket *) 726d83ca5acSGerrit Renker * Set S := new socket for this port pair 727d83ca5acSGerrit Renker * S.state = RESPOND 728d83ca5acSGerrit Renker * Choose S.ISS (initial seqno) or set from Init Cookies 729d83ca5acSGerrit Renker * Initialize S.GAR := S.ISS 730d83ca5acSGerrit Renker * Set S.ISR, S.GSR, S.SWL, S.SWH from packet or Init Cookies 731d83ca5acSGerrit Renker * Continue with S.state == RESPOND 732d83ca5acSGerrit Renker * (* A Response packet will be generated in Step 11 *) 733d83ca5acSGerrit Renker * Otherwise, 734d83ca5acSGerrit Renker * Generate Reset(No Connection) unless P.type == Reset 735d83ca5acSGerrit Renker * Drop packet and return 736d83ca5acSGerrit Renker * 737d83ca5acSGerrit Renker * NOTE: the check for the packet types is done in 738d83ca5acSGerrit Renker * dccp_rcv_state_process 739d83ca5acSGerrit Renker */ 7403df80d93SArnaldo Carvalho de Melo if (sk->sk_state == DCCP_LISTEN) { 7413df80d93SArnaldo Carvalho de Melo struct sock *nsk = dccp_v6_hnd_req(sk, skb); 7423df80d93SArnaldo Carvalho de Melo 74345329e71SArnaldo Carvalho de Melo if (nsk == NULL) 74445329e71SArnaldo Carvalho de Melo goto discard; 7453df80d93SArnaldo Carvalho de Melo /* 7463df80d93SArnaldo Carvalho de Melo * Queue it on the new socket if the new socket is active, 7473df80d93SArnaldo Carvalho de Melo * otherwise we just shortcircuit this and continue with 7483df80d93SArnaldo Carvalho de Melo * the new socket.. 7493df80d93SArnaldo Carvalho de Melo */ 7503df80d93SArnaldo Carvalho de Melo if (nsk != sk) { 7513df80d93SArnaldo Carvalho de Melo if (dccp_child_process(sk, nsk, skb)) 7523df80d93SArnaldo Carvalho de Melo goto reset; 75345329e71SArnaldo Carvalho de Melo if (opt_skb != NULL) 7543df80d93SArnaldo Carvalho de Melo __kfree_skb(opt_skb); 7553df80d93SArnaldo Carvalho de Melo return 0; 7563df80d93SArnaldo Carvalho de Melo } 7573df80d93SArnaldo Carvalho de Melo } 7583df80d93SArnaldo Carvalho de Melo 7593df80d93SArnaldo Carvalho de Melo if (dccp_rcv_state_process(sk, skb, dccp_hdr(skb), skb->len)) 7603df80d93SArnaldo Carvalho de Melo goto reset; 761fd169f15SDavid S. Miller if (opt_skb) { 76289e7e577SGerrit Renker /* XXX This is where we would goto ipv6_pktoptions. */ 763fd169f15SDavid S. Miller __kfree_skb(opt_skb); 764fd169f15SDavid S. Miller } 7653df80d93SArnaldo Carvalho de Melo return 0; 7663df80d93SArnaldo Carvalho de Melo 7673df80d93SArnaldo Carvalho de Melo reset: 768cfb6eeb4SYOSHIFUJI Hideaki dccp_v6_ctl_send_reset(sk, skb); 7693df80d93SArnaldo Carvalho de Melo discard: 77045329e71SArnaldo Carvalho de Melo if (opt_skb != NULL) 7713df80d93SArnaldo Carvalho de Melo __kfree_skb(opt_skb); 7723df80d93SArnaldo Carvalho de Melo kfree_skb(skb); 7733df80d93SArnaldo Carvalho de Melo return 0; 7743df80d93SArnaldo Carvalho de Melo } 7753df80d93SArnaldo Carvalho de Melo 776e5bbef20SHerbert Xu static int dccp_v6_rcv(struct sk_buff *skb) 7773df80d93SArnaldo Carvalho de Melo { 7783df80d93SArnaldo Carvalho de Melo const struct dccp_hdr *dh; 7793df80d93SArnaldo Carvalho de Melo struct sock *sk; 7806f4e5fffSGerrit Renker int min_cov; 7813df80d93SArnaldo Carvalho de Melo 7826f4e5fffSGerrit Renker /* Step 1: Check header basics */ 7833df80d93SArnaldo Carvalho de Melo 7843df80d93SArnaldo Carvalho de Melo if (dccp_invalid_packet(skb)) 7853df80d93SArnaldo Carvalho de Melo goto discard_it; 7863df80d93SArnaldo Carvalho de Melo 7876f4e5fffSGerrit Renker /* Step 1: If header checksum is incorrect, drop packet and return. */ 7880660e03fSArnaldo Carvalho de Melo if (dccp_v6_csum_finish(skb, &ipv6_hdr(skb)->saddr, 7890660e03fSArnaldo Carvalho de Melo &ipv6_hdr(skb)->daddr)) { 79059348b19SGerrit Renker DCCP_WARN("dropped packet with invalid checksum\n"); 7916f4e5fffSGerrit Renker goto discard_it; 7926f4e5fffSGerrit Renker } 7936f4e5fffSGerrit Renker 7943df80d93SArnaldo Carvalho de Melo dh = dccp_hdr(skb); 7953df80d93SArnaldo Carvalho de Melo 796fde20105SGerrit Renker DCCP_SKB_CB(skb)->dccpd_seq = dccp_hdr_seq(dh); 7973df80d93SArnaldo Carvalho de Melo DCCP_SKB_CB(skb)->dccpd_type = dh->dccph_type; 7983df80d93SArnaldo Carvalho de Melo 7993df80d93SArnaldo Carvalho de Melo if (dccp_packet_without_ack(skb)) 8003df80d93SArnaldo Carvalho de Melo DCCP_SKB_CB(skb)->dccpd_ack_seq = DCCP_PKT_WITHOUT_ACK_SEQ; 8013df80d93SArnaldo Carvalho de Melo else 8023df80d93SArnaldo Carvalho de Melo DCCP_SKB_CB(skb)->dccpd_ack_seq = dccp_hdr_ack_seq(skb); 8033df80d93SArnaldo Carvalho de Melo 8043df80d93SArnaldo Carvalho de Melo /* Step 2: 8053df80d93SArnaldo Carvalho de Melo * Look up flow ID in table and get corresponding socket */ 8069a1f27c4SArnaldo Carvalho de Melo sk = __inet6_lookup_skb(&dccp_hashinfo, skb, 8079a1f27c4SArnaldo Carvalho de Melo dh->dccph_sport, dh->dccph_dport); 8083df80d93SArnaldo Carvalho de Melo /* 8093df80d93SArnaldo Carvalho de Melo * Step 2: 8103df80d93SArnaldo Carvalho de Melo * If no socket ... 8113df80d93SArnaldo Carvalho de Melo */ 812d23c7107SGerrit Renker if (sk == NULL) { 813d23c7107SGerrit Renker dccp_pr_debug("failed to look up flow ID in table and " 814d23c7107SGerrit Renker "get corresponding socket\n"); 8153df80d93SArnaldo Carvalho de Melo goto no_dccp_socket; 816d23c7107SGerrit Renker } 8173df80d93SArnaldo Carvalho de Melo 8183df80d93SArnaldo Carvalho de Melo /* 8193df80d93SArnaldo Carvalho de Melo * Step 2: 8203df80d93SArnaldo Carvalho de Melo * ... or S.state == TIMEWAIT, 8213df80d93SArnaldo Carvalho de Melo * Generate Reset(No Connection) unless P.type == Reset 8223df80d93SArnaldo Carvalho de Melo * Drop packet and return 8233df80d93SArnaldo Carvalho de Melo */ 824d23c7107SGerrit Renker if (sk->sk_state == DCCP_TIME_WAIT) { 825d23c7107SGerrit Renker dccp_pr_debug("sk->sk_state == DCCP_TIME_WAIT: do_time_wait\n"); 826d23c7107SGerrit Renker inet_twsk_put(inet_twsk(sk)); 827d23c7107SGerrit Renker goto no_dccp_socket; 828d23c7107SGerrit Renker } 8293df80d93SArnaldo Carvalho de Melo 8306f4e5fffSGerrit Renker /* 8316f4e5fffSGerrit Renker * RFC 4340, sec. 9.2.1: Minimum Checksum Coverage 8326f4e5fffSGerrit Renker * o if MinCsCov = 0, only packets with CsCov = 0 are accepted 8336f4e5fffSGerrit Renker * o if MinCsCov > 0, also accept packets with CsCov >= MinCsCov 8346f4e5fffSGerrit Renker */ 8356f4e5fffSGerrit Renker min_cov = dccp_sk(sk)->dccps_pcrlen; 8366f4e5fffSGerrit Renker if (dh->dccph_cscov && (min_cov == 0 || dh->dccph_cscov < min_cov)) { 8376f4e5fffSGerrit Renker dccp_pr_debug("Packet CsCov %d does not satisfy MinCsCov %d\n", 8386f4e5fffSGerrit Renker dh->dccph_cscov, min_cov); 8396f4e5fffSGerrit Renker /* FIXME: send Data Dropped option (see also dccp_v4_rcv) */ 8406f4e5fffSGerrit Renker goto discard_and_relse; 8416f4e5fffSGerrit Renker } 8426f4e5fffSGerrit Renker 8433df80d93SArnaldo Carvalho de Melo if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb)) 8443df80d93SArnaldo Carvalho de Melo goto discard_and_relse; 8453df80d93SArnaldo Carvalho de Melo 84658a5a7b9SArnaldo Carvalho de Melo return sk_receive_skb(sk, skb, 1) ? -1 : 0; 8473df80d93SArnaldo Carvalho de Melo 8483df80d93SArnaldo Carvalho de Melo no_dccp_socket: 8493df80d93SArnaldo Carvalho de Melo if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) 8503df80d93SArnaldo Carvalho de Melo goto discard_it; 8513df80d93SArnaldo Carvalho de Melo /* 8523df80d93SArnaldo Carvalho de Melo * Step 2: 853d83ca5acSGerrit Renker * If no socket ... 8543df80d93SArnaldo Carvalho de Melo * Generate Reset(No Connection) unless P.type == Reset 8553df80d93SArnaldo Carvalho de Melo * Drop packet and return 8563df80d93SArnaldo Carvalho de Melo */ 8573df80d93SArnaldo Carvalho de Melo if (dh->dccph_type != DCCP_PKT_RESET) { 8583df80d93SArnaldo Carvalho de Melo DCCP_SKB_CB(skb)->dccpd_reset_code = 8593df80d93SArnaldo Carvalho de Melo DCCP_RESET_CODE_NO_CONNECTION; 860cfb6eeb4SYOSHIFUJI Hideaki dccp_v6_ctl_send_reset(sk, skb); 8613df80d93SArnaldo Carvalho de Melo } 862d23c7107SGerrit Renker 8633df80d93SArnaldo Carvalho de Melo discard_it: 8643df80d93SArnaldo Carvalho de Melo kfree_skb(skb); 8653df80d93SArnaldo Carvalho de Melo return 0; 8663df80d93SArnaldo Carvalho de Melo 8673df80d93SArnaldo Carvalho de Melo discard_and_relse: 8683df80d93SArnaldo Carvalho de Melo sock_put(sk); 8693df80d93SArnaldo Carvalho de Melo goto discard_it; 8703df80d93SArnaldo Carvalho de Melo } 8713df80d93SArnaldo Carvalho de Melo 87273c9e02cSGerrit Renker static int dccp_v6_connect(struct sock *sk, struct sockaddr *uaddr, 87373c9e02cSGerrit Renker int addr_len) 87473c9e02cSGerrit Renker { 87573c9e02cSGerrit Renker struct sockaddr_in6 *usin = (struct sockaddr_in6 *)uaddr; 87673c9e02cSGerrit Renker struct inet_connection_sock *icsk = inet_csk(sk); 87773c9e02cSGerrit Renker struct inet_sock *inet = inet_sk(sk); 87873c9e02cSGerrit Renker struct ipv6_pinfo *np = inet6_sk(sk); 87973c9e02cSGerrit Renker struct dccp_sock *dp = dccp_sk(sk); 88020c59de2SArnaud Ebalard struct in6_addr *saddr = NULL, *final_p, final; 88173c9e02cSGerrit Renker struct flowi fl; 88273c9e02cSGerrit Renker struct dst_entry *dst; 88373c9e02cSGerrit Renker int addr_type; 88473c9e02cSGerrit Renker int err; 88573c9e02cSGerrit Renker 88673c9e02cSGerrit Renker dp->dccps_role = DCCP_ROLE_CLIENT; 88773c9e02cSGerrit Renker 88873c9e02cSGerrit Renker if (addr_len < SIN6_LEN_RFC2133) 88973c9e02cSGerrit Renker return -EINVAL; 89073c9e02cSGerrit Renker 89173c9e02cSGerrit Renker if (usin->sin6_family != AF_INET6) 89273c9e02cSGerrit Renker return -EAFNOSUPPORT; 89373c9e02cSGerrit Renker 89473c9e02cSGerrit Renker memset(&fl, 0, sizeof(fl)); 89573c9e02cSGerrit Renker 89673c9e02cSGerrit Renker if (np->sndflow) { 89773c9e02cSGerrit Renker fl.fl6_flowlabel = usin->sin6_flowinfo & IPV6_FLOWINFO_MASK; 89873c9e02cSGerrit Renker IP6_ECN_flow_init(fl.fl6_flowlabel); 89973c9e02cSGerrit Renker if (fl.fl6_flowlabel & IPV6_FLOWLABEL_MASK) { 90073c9e02cSGerrit Renker struct ip6_flowlabel *flowlabel; 90173c9e02cSGerrit Renker flowlabel = fl6_sock_lookup(sk, fl.fl6_flowlabel); 90273c9e02cSGerrit Renker if (flowlabel == NULL) 90373c9e02cSGerrit Renker return -EINVAL; 90473c9e02cSGerrit Renker ipv6_addr_copy(&usin->sin6_addr, &flowlabel->dst); 90573c9e02cSGerrit Renker fl6_sock_release(flowlabel); 90673c9e02cSGerrit Renker } 90773c9e02cSGerrit Renker } 90873c9e02cSGerrit Renker /* 90973c9e02cSGerrit Renker * connect() to INADDR_ANY means loopback (BSD'ism). 91073c9e02cSGerrit Renker */ 91173c9e02cSGerrit Renker if (ipv6_addr_any(&usin->sin6_addr)) 91273c9e02cSGerrit Renker usin->sin6_addr.s6_addr[15] = 1; 91373c9e02cSGerrit Renker 91473c9e02cSGerrit Renker addr_type = ipv6_addr_type(&usin->sin6_addr); 91573c9e02cSGerrit Renker 91673c9e02cSGerrit Renker if (addr_type & IPV6_ADDR_MULTICAST) 91773c9e02cSGerrit Renker return -ENETUNREACH; 91873c9e02cSGerrit Renker 91973c9e02cSGerrit Renker if (addr_type & IPV6_ADDR_LINKLOCAL) { 92073c9e02cSGerrit Renker if (addr_len >= sizeof(struct sockaddr_in6) && 92173c9e02cSGerrit Renker usin->sin6_scope_id) { 92273c9e02cSGerrit Renker /* If interface is set while binding, indices 92373c9e02cSGerrit Renker * must coincide. 92473c9e02cSGerrit Renker */ 92573c9e02cSGerrit Renker if (sk->sk_bound_dev_if && 92673c9e02cSGerrit Renker sk->sk_bound_dev_if != usin->sin6_scope_id) 92773c9e02cSGerrit Renker return -EINVAL; 92873c9e02cSGerrit Renker 92973c9e02cSGerrit Renker sk->sk_bound_dev_if = usin->sin6_scope_id; 93073c9e02cSGerrit Renker } 93173c9e02cSGerrit Renker 93273c9e02cSGerrit Renker /* Connect to link-local address requires an interface */ 93373c9e02cSGerrit Renker if (!sk->sk_bound_dev_if) 93473c9e02cSGerrit Renker return -EINVAL; 93573c9e02cSGerrit Renker } 93673c9e02cSGerrit Renker 93773c9e02cSGerrit Renker ipv6_addr_copy(&np->daddr, &usin->sin6_addr); 93873c9e02cSGerrit Renker np->flow_label = fl.fl6_flowlabel; 93973c9e02cSGerrit Renker 94073c9e02cSGerrit Renker /* 94173c9e02cSGerrit Renker * DCCP over IPv4 94273c9e02cSGerrit Renker */ 94373c9e02cSGerrit Renker if (addr_type == IPV6_ADDR_MAPPED) { 94473c9e02cSGerrit Renker u32 exthdrlen = icsk->icsk_ext_hdr_len; 94573c9e02cSGerrit Renker struct sockaddr_in sin; 94673c9e02cSGerrit Renker 94773c9e02cSGerrit Renker SOCK_DEBUG(sk, "connect: ipv4 mapped\n"); 94873c9e02cSGerrit Renker 94973c9e02cSGerrit Renker if (__ipv6_only_sock(sk)) 95073c9e02cSGerrit Renker return -ENETUNREACH; 95173c9e02cSGerrit Renker 95273c9e02cSGerrit Renker sin.sin_family = AF_INET; 95373c9e02cSGerrit Renker sin.sin_port = usin->sin6_port; 95473c9e02cSGerrit Renker sin.sin_addr.s_addr = usin->sin6_addr.s6_addr32[3]; 95573c9e02cSGerrit Renker 95673c9e02cSGerrit Renker icsk->icsk_af_ops = &dccp_ipv6_mapped; 95773c9e02cSGerrit Renker sk->sk_backlog_rcv = dccp_v4_do_rcv; 95873c9e02cSGerrit Renker 95973c9e02cSGerrit Renker err = dccp_v4_connect(sk, (struct sockaddr *)&sin, sizeof(sin)); 96073c9e02cSGerrit Renker if (err) { 96173c9e02cSGerrit Renker icsk->icsk_ext_hdr_len = exthdrlen; 96273c9e02cSGerrit Renker icsk->icsk_af_ops = &dccp_ipv6_af_ops; 96373c9e02cSGerrit Renker sk->sk_backlog_rcv = dccp_v6_do_rcv; 96473c9e02cSGerrit Renker goto failure; 96573c9e02cSGerrit Renker } 966c720c7e8SEric Dumazet ipv6_addr_set_v4mapped(inet->inet_saddr, &np->saddr); 967c720c7e8SEric Dumazet ipv6_addr_set_v4mapped(inet->inet_rcv_saddr, &np->rcv_saddr); 96873c9e02cSGerrit Renker 96973c9e02cSGerrit Renker return err; 97073c9e02cSGerrit Renker } 97173c9e02cSGerrit Renker 97273c9e02cSGerrit Renker if (!ipv6_addr_any(&np->rcv_saddr)) 97373c9e02cSGerrit Renker saddr = &np->rcv_saddr; 97473c9e02cSGerrit Renker 97573c9e02cSGerrit Renker fl.proto = IPPROTO_DCCP; 97673c9e02cSGerrit Renker ipv6_addr_copy(&fl.fl6_dst, &np->daddr); 97773c9e02cSGerrit Renker ipv6_addr_copy(&fl.fl6_src, saddr ? saddr : &np->saddr); 97873c9e02cSGerrit Renker fl.oif = sk->sk_bound_dev_if; 97973c9e02cSGerrit Renker fl.fl_ip_dport = usin->sin6_port; 980c720c7e8SEric Dumazet fl.fl_ip_sport = inet->inet_sport; 98173c9e02cSGerrit Renker security_sk_classify_flow(sk, &fl); 98273c9e02cSGerrit Renker 98320c59de2SArnaud Ebalard final_p = fl6_update_dst(&fl, np->opt, &final); 98473c9e02cSGerrit Renker 98573c9e02cSGerrit Renker err = ip6_dst_lookup(sk, &dst, &fl); 98673c9e02cSGerrit Renker if (err) 98773c9e02cSGerrit Renker goto failure; 98873c9e02cSGerrit Renker 98973c9e02cSGerrit Renker if (final_p) 99073c9e02cSGerrit Renker ipv6_addr_copy(&fl.fl6_dst, final_p); 99173c9e02cSGerrit Renker 99252479b62SAlexey Dobriyan err = __xfrm_lookup(sock_net(sk), &dst, &fl, sk, XFRM_LOOKUP_WAIT); 99314e50e57SDavid S. Miller if (err < 0) { 99414e50e57SDavid S. Miller if (err == -EREMOTE) 99514e50e57SDavid S. Miller err = ip6_dst_blackhole(sk, &dst, &fl); 99673c9e02cSGerrit Renker if (err < 0) 99773c9e02cSGerrit Renker goto failure; 99814e50e57SDavid S. Miller } 99973c9e02cSGerrit Renker 100073c9e02cSGerrit Renker if (saddr == NULL) { 100173c9e02cSGerrit Renker saddr = &fl.fl6_src; 100273c9e02cSGerrit Renker ipv6_addr_copy(&np->rcv_saddr, saddr); 100373c9e02cSGerrit Renker } 100473c9e02cSGerrit Renker 100573c9e02cSGerrit Renker /* set the source address */ 100673c9e02cSGerrit Renker ipv6_addr_copy(&np->saddr, saddr); 1007c720c7e8SEric Dumazet inet->inet_rcv_saddr = LOOPBACK4_IPV6; 100873c9e02cSGerrit Renker 100973c9e02cSGerrit Renker __ip6_dst_store(sk, dst, NULL, NULL); 101073c9e02cSGerrit Renker 101173c9e02cSGerrit Renker icsk->icsk_ext_hdr_len = 0; 101273c9e02cSGerrit Renker if (np->opt != NULL) 101373c9e02cSGerrit Renker icsk->icsk_ext_hdr_len = (np->opt->opt_flen + 101473c9e02cSGerrit Renker np->opt->opt_nflen); 101573c9e02cSGerrit Renker 1016c720c7e8SEric Dumazet inet->inet_dport = usin->sin6_port; 101773c9e02cSGerrit Renker 101873c9e02cSGerrit Renker dccp_set_state(sk, DCCP_REQUESTING); 101973c9e02cSGerrit Renker err = inet6_hash_connect(&dccp_death_row, sk); 102073c9e02cSGerrit Renker if (err) 102173c9e02cSGerrit Renker goto late_failure; 1022d7f7365fSGerrit Renker 1023d7f7365fSGerrit Renker dp->dccps_iss = secure_dccpv6_sequence_number(np->saddr.s6_addr32, 102473c9e02cSGerrit Renker np->daddr.s6_addr32, 1025c720c7e8SEric Dumazet inet->inet_sport, 1026c720c7e8SEric Dumazet inet->inet_dport); 102773c9e02cSGerrit Renker err = dccp_connect(sk); 102873c9e02cSGerrit Renker if (err) 102973c9e02cSGerrit Renker goto late_failure; 103073c9e02cSGerrit Renker 103173c9e02cSGerrit Renker return 0; 103273c9e02cSGerrit Renker 103373c9e02cSGerrit Renker late_failure: 103473c9e02cSGerrit Renker dccp_set_state(sk, DCCP_CLOSED); 103573c9e02cSGerrit Renker __sk_dst_reset(sk); 103673c9e02cSGerrit Renker failure: 1037c720c7e8SEric Dumazet inet->inet_dport = 0; 103873c9e02cSGerrit Renker sk->sk_route_caps = 0; 103973c9e02cSGerrit Renker return err; 104073c9e02cSGerrit Renker } 104173c9e02cSGerrit Renker 10423b401a81SStephen Hemminger static const struct inet_connection_sock_af_ops dccp_ipv6_af_ops = { 10433df80d93SArnaldo Carvalho de Melo .queue_xmit = inet6_csk_xmit, 10443df80d93SArnaldo Carvalho de Melo .send_check = dccp_v6_send_check, 10453df80d93SArnaldo Carvalho de Melo .rebuild_header = inet6_sk_rebuild_header, 10463df80d93SArnaldo Carvalho de Melo .conn_request = dccp_v6_conn_request, 10473df80d93SArnaldo Carvalho de Melo .syn_recv_sock = dccp_v6_request_recv_sock, 10483df80d93SArnaldo Carvalho de Melo .net_header_len = sizeof(struct ipv6hdr), 10493df80d93SArnaldo Carvalho de Melo .setsockopt = ipv6_setsockopt, 10503df80d93SArnaldo Carvalho de Melo .getsockopt = ipv6_getsockopt, 1051543d9cfeSArnaldo Carvalho de Melo .addr2sockaddr = inet6_csk_addr2sockaddr, 1052543d9cfeSArnaldo Carvalho de Melo .sockaddr_len = sizeof(struct sockaddr_in6), 1053ab1e0a13SArnaldo Carvalho de Melo .bind_conflict = inet6_csk_bind_conflict, 10543fdadf7dSDmitry Mishin #ifdef CONFIG_COMPAT 10553fdadf7dSDmitry Mishin .compat_setsockopt = compat_ipv6_setsockopt, 10563fdadf7dSDmitry Mishin .compat_getsockopt = compat_ipv6_getsockopt, 10573fdadf7dSDmitry Mishin #endif 10583df80d93SArnaldo Carvalho de Melo }; 10593df80d93SArnaldo Carvalho de Melo 10603df80d93SArnaldo Carvalho de Melo /* 10613df80d93SArnaldo Carvalho de Melo * DCCP over IPv4 via INET6 API 10623df80d93SArnaldo Carvalho de Melo */ 10633b401a81SStephen Hemminger static const struct inet_connection_sock_af_ops dccp_ipv6_mapped = { 10643df80d93SArnaldo Carvalho de Melo .queue_xmit = ip_queue_xmit, 10653df80d93SArnaldo Carvalho de Melo .send_check = dccp_v4_send_check, 10663df80d93SArnaldo Carvalho de Melo .rebuild_header = inet_sk_rebuild_header, 10673df80d93SArnaldo Carvalho de Melo .conn_request = dccp_v6_conn_request, 10683df80d93SArnaldo Carvalho de Melo .syn_recv_sock = dccp_v6_request_recv_sock, 10693df80d93SArnaldo Carvalho de Melo .net_header_len = sizeof(struct iphdr), 10703df80d93SArnaldo Carvalho de Melo .setsockopt = ipv6_setsockopt, 10713df80d93SArnaldo Carvalho de Melo .getsockopt = ipv6_getsockopt, 1072543d9cfeSArnaldo Carvalho de Melo .addr2sockaddr = inet6_csk_addr2sockaddr, 1073543d9cfeSArnaldo Carvalho de Melo .sockaddr_len = sizeof(struct sockaddr_in6), 10743fdadf7dSDmitry Mishin #ifdef CONFIG_COMPAT 10753fdadf7dSDmitry Mishin .compat_setsockopt = compat_ipv6_setsockopt, 10763fdadf7dSDmitry Mishin .compat_getsockopt = compat_ipv6_getsockopt, 10773fdadf7dSDmitry Mishin #endif 10783df80d93SArnaldo Carvalho de Melo }; 10793df80d93SArnaldo Carvalho de Melo 10803df80d93SArnaldo Carvalho de Melo /* NOTE: A lot of things set to zero explicitly by call to 10813df80d93SArnaldo Carvalho de Melo * sk_alloc() so need not be done here. 10823df80d93SArnaldo Carvalho de Melo */ 10833df80d93SArnaldo Carvalho de Melo static int dccp_v6_init_sock(struct sock *sk) 10843df80d93SArnaldo Carvalho de Melo { 108572478873SArnaldo Carvalho de Melo static __u8 dccp_v6_ctl_sock_initialized; 108672478873SArnaldo Carvalho de Melo int err = dccp_init_sock(sk, dccp_v6_ctl_sock_initialized); 10873df80d93SArnaldo Carvalho de Melo 108872478873SArnaldo Carvalho de Melo if (err == 0) { 108972478873SArnaldo Carvalho de Melo if (unlikely(!dccp_v6_ctl_sock_initialized)) 109072478873SArnaldo Carvalho de Melo dccp_v6_ctl_sock_initialized = 1; 10913df80d93SArnaldo Carvalho de Melo inet_csk(sk)->icsk_af_ops = &dccp_ipv6_af_ops; 109272478873SArnaldo Carvalho de Melo } 10933df80d93SArnaldo Carvalho de Melo 10943df80d93SArnaldo Carvalho de Melo return err; 10953df80d93SArnaldo Carvalho de Melo } 10963df80d93SArnaldo Carvalho de Melo 10977d06b2e0SBrian Haley static void dccp_v6_destroy_sock(struct sock *sk) 10983df80d93SArnaldo Carvalho de Melo { 10993e0fadc5SArnaldo Carvalho de Melo dccp_destroy_sock(sk); 11007d06b2e0SBrian Haley inet6_destroy_sock(sk); 11013df80d93SArnaldo Carvalho de Melo } 11023df80d93SArnaldo Carvalho de Melo 110373c9e02cSGerrit Renker static struct timewait_sock_ops dccp6_timewait_sock_ops = { 110473c9e02cSGerrit Renker .twsk_obj_size = sizeof(struct dccp6_timewait_sock), 110573c9e02cSGerrit Renker }; 110673c9e02cSGerrit Renker 11073df80d93SArnaldo Carvalho de Melo static struct proto dccp_v6_prot = { 11083df80d93SArnaldo Carvalho de Melo .name = "DCCPv6", 11093df80d93SArnaldo Carvalho de Melo .owner = THIS_MODULE, 11103df80d93SArnaldo Carvalho de Melo .close = dccp_close, 11113df80d93SArnaldo Carvalho de Melo .connect = dccp_v6_connect, 11123df80d93SArnaldo Carvalho de Melo .disconnect = dccp_disconnect, 11133df80d93SArnaldo Carvalho de Melo .ioctl = dccp_ioctl, 11143df80d93SArnaldo Carvalho de Melo .init = dccp_v6_init_sock, 11153df80d93SArnaldo Carvalho de Melo .setsockopt = dccp_setsockopt, 11163df80d93SArnaldo Carvalho de Melo .getsockopt = dccp_getsockopt, 11173df80d93SArnaldo Carvalho de Melo .sendmsg = dccp_sendmsg, 11183df80d93SArnaldo Carvalho de Melo .recvmsg = dccp_recvmsg, 11193df80d93SArnaldo Carvalho de Melo .backlog_rcv = dccp_v6_do_rcv, 11203df80d93SArnaldo Carvalho de Melo .hash = dccp_v6_hash, 1121ab1e0a13SArnaldo Carvalho de Melo .unhash = inet_unhash, 11223df80d93SArnaldo Carvalho de Melo .accept = inet_csk_accept, 1123ab1e0a13SArnaldo Carvalho de Melo .get_port = inet_csk_get_port, 11243df80d93SArnaldo Carvalho de Melo .shutdown = dccp_shutdown, 11253df80d93SArnaldo Carvalho de Melo .destroy = dccp_v6_destroy_sock, 11263df80d93SArnaldo Carvalho de Melo .orphan_count = &dccp_orphan_count, 11273df80d93SArnaldo Carvalho de Melo .max_header = MAX_DCCP_HEADER, 11283df80d93SArnaldo Carvalho de Melo .obj_size = sizeof(struct dccp6_sock), 11293ab5aee7SEric Dumazet .slab_flags = SLAB_DESTROY_BY_RCU, 11303df80d93SArnaldo Carvalho de Melo .rsk_prot = &dccp6_request_sock_ops, 11316d6ee43eSArnaldo Carvalho de Melo .twsk_prot = &dccp6_timewait_sock_ops, 113239d8cda7SPavel Emelyanov .h.hashinfo = &dccp_hashinfo, 1133543d9cfeSArnaldo Carvalho de Melo #ifdef CONFIG_COMPAT 1134543d9cfeSArnaldo Carvalho de Melo .compat_setsockopt = compat_dccp_setsockopt, 1135543d9cfeSArnaldo Carvalho de Melo .compat_getsockopt = compat_dccp_getsockopt, 1136543d9cfeSArnaldo Carvalho de Melo #endif 11373df80d93SArnaldo Carvalho de Melo }; 11383df80d93SArnaldo Carvalho de Melo 113941135cc8SAlexey Dobriyan static const struct inet6_protocol dccp_v6_protocol = { 11403df80d93SArnaldo Carvalho de Melo .handler = dccp_v6_rcv, 11413df80d93SArnaldo Carvalho de Melo .err_handler = dccp_v6_err, 11423df80d93SArnaldo Carvalho de Melo .flags = INET6_PROTO_NOPOLICY | INET6_PROTO_FINAL, 11433df80d93SArnaldo Carvalho de Melo }; 11443df80d93SArnaldo Carvalho de Melo 11455708e868SAlexey Dobriyan static const struct proto_ops inet6_dccp_ops = { 11463df80d93SArnaldo Carvalho de Melo .family = PF_INET6, 11473df80d93SArnaldo Carvalho de Melo .owner = THIS_MODULE, 11483df80d93SArnaldo Carvalho de Melo .release = inet6_release, 11493df80d93SArnaldo Carvalho de Melo .bind = inet6_bind, 11503df80d93SArnaldo Carvalho de Melo .connect = inet_stream_connect, 11513df80d93SArnaldo Carvalho de Melo .socketpair = sock_no_socketpair, 11523df80d93SArnaldo Carvalho de Melo .accept = inet_accept, 11533df80d93SArnaldo Carvalho de Melo .getname = inet6_getname, 11543df80d93SArnaldo Carvalho de Melo .poll = dccp_poll, 11553df80d93SArnaldo Carvalho de Melo .ioctl = inet6_ioctl, 11563df80d93SArnaldo Carvalho de Melo .listen = inet_dccp_listen, 11573df80d93SArnaldo Carvalho de Melo .shutdown = inet_shutdown, 11583df80d93SArnaldo Carvalho de Melo .setsockopt = sock_common_setsockopt, 11593df80d93SArnaldo Carvalho de Melo .getsockopt = sock_common_getsockopt, 11603df80d93SArnaldo Carvalho de Melo .sendmsg = inet_sendmsg, 11613df80d93SArnaldo Carvalho de Melo .recvmsg = sock_common_recvmsg, 11623df80d93SArnaldo Carvalho de Melo .mmap = sock_no_mmap, 11633df80d93SArnaldo Carvalho de Melo .sendpage = sock_no_sendpage, 1164543d9cfeSArnaldo Carvalho de Melo #ifdef CONFIG_COMPAT 1165543d9cfeSArnaldo Carvalho de Melo .compat_setsockopt = compat_sock_common_setsockopt, 1166543d9cfeSArnaldo Carvalho de Melo .compat_getsockopt = compat_sock_common_getsockopt, 1167543d9cfeSArnaldo Carvalho de Melo #endif 11683df80d93SArnaldo Carvalho de Melo }; 11693df80d93SArnaldo Carvalho de Melo 11703df80d93SArnaldo Carvalho de Melo static struct inet_protosw dccp_v6_protosw = { 11713df80d93SArnaldo Carvalho de Melo .type = SOCK_DCCP, 11723df80d93SArnaldo Carvalho de Melo .protocol = IPPROTO_DCCP, 11733df80d93SArnaldo Carvalho de Melo .prot = &dccp_v6_prot, 11743df80d93SArnaldo Carvalho de Melo .ops = &inet6_dccp_ops, 1175d83d8461SArnaldo Carvalho de Melo .flags = INET_PROTOSW_ICSK, 11763df80d93SArnaldo Carvalho de Melo }; 11773df80d93SArnaldo Carvalho de Melo 11782c8c1e72SAlexey Dobriyan static int __net_init dccp_v6_init_net(struct net *net) 11798231bd27SPavel Emelyanov { 1180d14a0ebdSGerrit Renker if (dccp_hashinfo.bhash == NULL) 1181d14a0ebdSGerrit Renker return -ESOCKTNOSUPPORT; 1182334527d3SPavel Emelyanov 1183d14a0ebdSGerrit Renker return inet_ctl_sock_create(&net->dccp.v6_ctl_sk, PF_INET6, 1184334527d3SPavel Emelyanov SOCK_DCCP, IPPROTO_DCCP, net); 11858231bd27SPavel Emelyanov } 11868231bd27SPavel Emelyanov 11872c8c1e72SAlexey Dobriyan static void __net_exit dccp_v6_exit_net(struct net *net) 11888231bd27SPavel Emelyanov { 1189334527d3SPavel Emelyanov inet_ctl_sock_destroy(net->dccp.v6_ctl_sk); 11908231bd27SPavel Emelyanov } 11918231bd27SPavel Emelyanov 11928231bd27SPavel Emelyanov static struct pernet_operations dccp_v6_ops = { 11938231bd27SPavel Emelyanov .init = dccp_v6_init_net, 11948231bd27SPavel Emelyanov .exit = dccp_v6_exit_net, 11958231bd27SPavel Emelyanov }; 11968231bd27SPavel Emelyanov 11973df80d93SArnaldo Carvalho de Melo static int __init dccp_v6_init(void) 11983df80d93SArnaldo Carvalho de Melo { 11993df80d93SArnaldo Carvalho de Melo int err = proto_register(&dccp_v6_prot, 1); 12003df80d93SArnaldo Carvalho de Melo 12013df80d93SArnaldo Carvalho de Melo if (err != 0) 12023df80d93SArnaldo Carvalho de Melo goto out; 12033df80d93SArnaldo Carvalho de Melo 12043df80d93SArnaldo Carvalho de Melo err = inet6_add_protocol(&dccp_v6_protocol, IPPROTO_DCCP); 12053df80d93SArnaldo Carvalho de Melo if (err != 0) 12063df80d93SArnaldo Carvalho de Melo goto out_unregister_proto; 12073df80d93SArnaldo Carvalho de Melo 12083df80d93SArnaldo Carvalho de Melo inet6_register_protosw(&dccp_v6_protosw); 120972478873SArnaldo Carvalho de Melo 12108231bd27SPavel Emelyanov err = register_pernet_subsys(&dccp_v6_ops); 12118231bd27SPavel Emelyanov if (err != 0) 12128231bd27SPavel Emelyanov goto out_destroy_ctl_sock; 12133df80d93SArnaldo Carvalho de Melo out: 12143df80d93SArnaldo Carvalho de Melo return err; 12158231bd27SPavel Emelyanov 12168231bd27SPavel Emelyanov out_destroy_ctl_sock: 121772478873SArnaldo Carvalho de Melo inet6_del_protocol(&dccp_v6_protocol, IPPROTO_DCCP); 121872478873SArnaldo Carvalho de Melo inet6_unregister_protosw(&dccp_v6_protosw); 12193df80d93SArnaldo Carvalho de Melo out_unregister_proto: 12203df80d93SArnaldo Carvalho de Melo proto_unregister(&dccp_v6_prot); 12213df80d93SArnaldo Carvalho de Melo goto out; 12223df80d93SArnaldo Carvalho de Melo } 12233df80d93SArnaldo Carvalho de Melo 12243df80d93SArnaldo Carvalho de Melo static void __exit dccp_v6_exit(void) 12253df80d93SArnaldo Carvalho de Melo { 12268231bd27SPavel Emelyanov unregister_pernet_subsys(&dccp_v6_ops); 12273df80d93SArnaldo Carvalho de Melo inet6_del_protocol(&dccp_v6_protocol, IPPROTO_DCCP); 12283df80d93SArnaldo Carvalho de Melo inet6_unregister_protosw(&dccp_v6_protosw); 12293df80d93SArnaldo Carvalho de Melo proto_unregister(&dccp_v6_prot); 12303df80d93SArnaldo Carvalho de Melo } 12313df80d93SArnaldo Carvalho de Melo 12323df80d93SArnaldo Carvalho de Melo module_init(dccp_v6_init); 12333df80d93SArnaldo Carvalho de Melo module_exit(dccp_v6_exit); 12343df80d93SArnaldo Carvalho de Melo 12353df80d93SArnaldo Carvalho de Melo /* 12363df80d93SArnaldo Carvalho de Melo * __stringify doesn't likes enums, so use SOCK_DCCP (6) and IPPROTO_DCCP (33) 12373df80d93SArnaldo Carvalho de Melo * values directly, Also cover the case where the protocol is not specified, 12383df80d93SArnaldo Carvalho de Melo * i.e. net-pf-PF_INET6-proto-0-type-SOCK_DCCP 12393df80d93SArnaldo Carvalho de Melo */ 12407131c6c7SJean Delvare MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_INET6, 33, 6); 12417131c6c7SJean Delvare MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_INET6, 0, 6); 12423df80d93SArnaldo Carvalho de Melo MODULE_LICENSE("GPL"); 12433df80d93SArnaldo Carvalho de Melo MODULE_AUTHOR("Arnaldo Carvalho de Melo <acme@mandriva.com>"); 12443df80d93SArnaldo Carvalho de Melo MODULE_DESCRIPTION("DCCPv6 - Datagram Congestion Controlled Protocol"); 1245