18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci *	DCCP over IPv6
48c2ecf20Sopenharmony_ci *	Linux INET6 implementation
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci *	Based on net/dccp6/ipv6.c
78c2ecf20Sopenharmony_ci *
88c2ecf20Sopenharmony_ci *	Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
98c2ecf20Sopenharmony_ci */
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci#include <linux/module.h>
128c2ecf20Sopenharmony_ci#include <linux/random.h>
138c2ecf20Sopenharmony_ci#include <linux/slab.h>
148c2ecf20Sopenharmony_ci#include <linux/xfrm.h>
158c2ecf20Sopenharmony_ci#include <linux/string.h>
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci#include <net/addrconf.h>
188c2ecf20Sopenharmony_ci#include <net/inet_common.h>
198c2ecf20Sopenharmony_ci#include <net/inet_hashtables.h>
208c2ecf20Sopenharmony_ci#include <net/inet_sock.h>
218c2ecf20Sopenharmony_ci#include <net/inet6_connection_sock.h>
228c2ecf20Sopenharmony_ci#include <net/inet6_hashtables.h>
238c2ecf20Sopenharmony_ci#include <net/ip6_route.h>
248c2ecf20Sopenharmony_ci#include <net/ipv6.h>
258c2ecf20Sopenharmony_ci#include <net/protocol.h>
268c2ecf20Sopenharmony_ci#include <net/transp_v6.h>
278c2ecf20Sopenharmony_ci#include <net/ip6_checksum.h>
288c2ecf20Sopenharmony_ci#include <net/xfrm.h>
298c2ecf20Sopenharmony_ci#include <net/secure_seq.h>
308c2ecf20Sopenharmony_ci#include <net/sock.h>
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ci#include "dccp.h"
338c2ecf20Sopenharmony_ci#include "ipv6.h"
348c2ecf20Sopenharmony_ci#include "feat.h"
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ci/* The per-net dccp.v6_ctl_sk is used for sending RSTs and ACKs */
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_cistatic const struct inet_connection_sock_af_ops dccp_ipv6_mapped;
398c2ecf20Sopenharmony_cistatic const struct inet_connection_sock_af_ops dccp_ipv6_af_ops;
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ci/* add pseudo-header to DCCP checksum stored in skb->csum */
428c2ecf20Sopenharmony_cistatic inline __sum16 dccp_v6_csum_finish(struct sk_buff *skb,
438c2ecf20Sopenharmony_ci				      const struct in6_addr *saddr,
448c2ecf20Sopenharmony_ci				      const struct in6_addr *daddr)
458c2ecf20Sopenharmony_ci{
468c2ecf20Sopenharmony_ci	return csum_ipv6_magic(saddr, daddr, skb->len, IPPROTO_DCCP, skb->csum);
478c2ecf20Sopenharmony_ci}
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_cistatic inline void dccp_v6_send_check(struct sock *sk, struct sk_buff *skb)
508c2ecf20Sopenharmony_ci{
518c2ecf20Sopenharmony_ci	struct ipv6_pinfo *np = inet6_sk(sk);
528c2ecf20Sopenharmony_ci	struct dccp_hdr *dh = dccp_hdr(skb);
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ci	dccp_csum_outgoing(skb);
558c2ecf20Sopenharmony_ci	dh->dccph_checksum = dccp_v6_csum_finish(skb, &np->saddr, &sk->sk_v6_daddr);
568c2ecf20Sopenharmony_ci}
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_cistatic inline __u64 dccp_v6_init_sequence(struct sk_buff *skb)
598c2ecf20Sopenharmony_ci{
608c2ecf20Sopenharmony_ci	return secure_dccpv6_sequence_number(ipv6_hdr(skb)->daddr.s6_addr32,
618c2ecf20Sopenharmony_ci					     ipv6_hdr(skb)->saddr.s6_addr32,
628c2ecf20Sopenharmony_ci					     dccp_hdr(skb)->dccph_dport,
638c2ecf20Sopenharmony_ci					     dccp_hdr(skb)->dccph_sport     );
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci}
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_cistatic int dccp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
688c2ecf20Sopenharmony_ci			u8 type, u8 code, int offset, __be32 info)
698c2ecf20Sopenharmony_ci{
708c2ecf20Sopenharmony_ci	const struct ipv6hdr *hdr;
718c2ecf20Sopenharmony_ci	const struct dccp_hdr *dh;
728c2ecf20Sopenharmony_ci	struct dccp_sock *dp;
738c2ecf20Sopenharmony_ci	struct ipv6_pinfo *np;
748c2ecf20Sopenharmony_ci	struct sock *sk;
758c2ecf20Sopenharmony_ci	int err;
768c2ecf20Sopenharmony_ci	__u64 seq;
778c2ecf20Sopenharmony_ci	struct net *net = dev_net(skb->dev);
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci	if (!pskb_may_pull(skb, offset + sizeof(*dh)))
808c2ecf20Sopenharmony_ci		return -EINVAL;
818c2ecf20Sopenharmony_ci	dh = (struct dccp_hdr *)(skb->data + offset);
828c2ecf20Sopenharmony_ci	if (!pskb_may_pull(skb, offset + __dccp_basic_hdr_len(dh)))
838c2ecf20Sopenharmony_ci		return -EINVAL;
848c2ecf20Sopenharmony_ci	hdr = (const struct ipv6hdr *)skb->data;
858c2ecf20Sopenharmony_ci	dh = (struct dccp_hdr *)(skb->data + offset);
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_ci	sk = __inet6_lookup_established(net, &dccp_hashinfo,
888c2ecf20Sopenharmony_ci					&hdr->daddr, dh->dccph_dport,
898c2ecf20Sopenharmony_ci					&hdr->saddr, ntohs(dh->dccph_sport),
908c2ecf20Sopenharmony_ci					inet6_iif(skb), 0);
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ci	if (!sk) {
938c2ecf20Sopenharmony_ci		__ICMP6_INC_STATS(net, __in6_dev_get(skb->dev),
948c2ecf20Sopenharmony_ci				  ICMP6_MIB_INERRORS);
958c2ecf20Sopenharmony_ci		return -ENOENT;
968c2ecf20Sopenharmony_ci	}
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci	if (sk->sk_state == DCCP_TIME_WAIT) {
998c2ecf20Sopenharmony_ci		inet_twsk_put(inet_twsk(sk));
1008c2ecf20Sopenharmony_ci		return 0;
1018c2ecf20Sopenharmony_ci	}
1028c2ecf20Sopenharmony_ci	seq = dccp_hdr_seq(dh);
1038c2ecf20Sopenharmony_ci	if (sk->sk_state == DCCP_NEW_SYN_RECV) {
1048c2ecf20Sopenharmony_ci		dccp_req_err(sk, seq);
1058c2ecf20Sopenharmony_ci		return 0;
1068c2ecf20Sopenharmony_ci	}
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_ci	bh_lock_sock(sk);
1098c2ecf20Sopenharmony_ci	if (sock_owned_by_user(sk))
1108c2ecf20Sopenharmony_ci		__NET_INC_STATS(net, LINUX_MIB_LOCKDROPPEDICMPS);
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_ci	if (sk->sk_state == DCCP_CLOSED)
1138c2ecf20Sopenharmony_ci		goto out;
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_ci	dp = dccp_sk(sk);
1168c2ecf20Sopenharmony_ci	if ((1 << sk->sk_state) & ~(DCCPF_REQUESTING | DCCPF_LISTEN) &&
1178c2ecf20Sopenharmony_ci	    !between48(seq, dp->dccps_awl, dp->dccps_awh)) {
1188c2ecf20Sopenharmony_ci		__NET_INC_STATS(net, LINUX_MIB_OUTOFWINDOWICMPS);
1198c2ecf20Sopenharmony_ci		goto out;
1208c2ecf20Sopenharmony_ci	}
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_ci	np = inet6_sk(sk);
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_ci	if (type == NDISC_REDIRECT) {
1258c2ecf20Sopenharmony_ci		if (!sock_owned_by_user(sk)) {
1268c2ecf20Sopenharmony_ci			struct dst_entry *dst = __sk_dst_check(sk, np->dst_cookie);
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_ci			if (dst)
1298c2ecf20Sopenharmony_ci				dst->ops->redirect(dst, sk, skb);
1308c2ecf20Sopenharmony_ci		}
1318c2ecf20Sopenharmony_ci		goto out;
1328c2ecf20Sopenharmony_ci	}
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_ci	if (type == ICMPV6_PKT_TOOBIG) {
1358c2ecf20Sopenharmony_ci		struct dst_entry *dst = NULL;
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_ci		if (!ip6_sk_accept_pmtu(sk))
1388c2ecf20Sopenharmony_ci			goto out;
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_ci		if (sock_owned_by_user(sk))
1418c2ecf20Sopenharmony_ci			goto out;
1428c2ecf20Sopenharmony_ci		if ((1 << sk->sk_state) & (DCCPF_LISTEN | DCCPF_CLOSED))
1438c2ecf20Sopenharmony_ci			goto out;
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_ci		dst = inet6_csk_update_pmtu(sk, ntohl(info));
1468c2ecf20Sopenharmony_ci		if (!dst)
1478c2ecf20Sopenharmony_ci			goto out;
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_ci		if (inet_csk(sk)->icsk_pmtu_cookie > dst_mtu(dst))
1508c2ecf20Sopenharmony_ci			dccp_sync_mss(sk, dst_mtu(dst));
1518c2ecf20Sopenharmony_ci		goto out;
1528c2ecf20Sopenharmony_ci	}
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_ci	icmpv6_err_convert(type, code, &err);
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_ci	/* Might be for an request_sock */
1578c2ecf20Sopenharmony_ci	switch (sk->sk_state) {
1588c2ecf20Sopenharmony_ci	case DCCP_REQUESTING:
1598c2ecf20Sopenharmony_ci	case DCCP_RESPOND:  /* Cannot happen.
1608c2ecf20Sopenharmony_ci			       It can, it SYNs are crossed. --ANK */
1618c2ecf20Sopenharmony_ci		if (!sock_owned_by_user(sk)) {
1628c2ecf20Sopenharmony_ci			__DCCP_INC_STATS(DCCP_MIB_ATTEMPTFAILS);
1638c2ecf20Sopenharmony_ci			sk->sk_err = err;
1648c2ecf20Sopenharmony_ci			/*
1658c2ecf20Sopenharmony_ci			 * Wake people up to see the error
1668c2ecf20Sopenharmony_ci			 * (see connect in sock.c)
1678c2ecf20Sopenharmony_ci			 */
1688c2ecf20Sopenharmony_ci			sk->sk_error_report(sk);
1698c2ecf20Sopenharmony_ci			dccp_done(sk);
1708c2ecf20Sopenharmony_ci		} else
1718c2ecf20Sopenharmony_ci			sk->sk_err_soft = err;
1728c2ecf20Sopenharmony_ci		goto out;
1738c2ecf20Sopenharmony_ci	}
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_ci	if (!sock_owned_by_user(sk) && np->recverr) {
1768c2ecf20Sopenharmony_ci		sk->sk_err = err;
1778c2ecf20Sopenharmony_ci		sk->sk_error_report(sk);
1788c2ecf20Sopenharmony_ci	} else
1798c2ecf20Sopenharmony_ci		sk->sk_err_soft = err;
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_ciout:
1828c2ecf20Sopenharmony_ci	bh_unlock_sock(sk);
1838c2ecf20Sopenharmony_ci	sock_put(sk);
1848c2ecf20Sopenharmony_ci	return 0;
1858c2ecf20Sopenharmony_ci}
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_cistatic int dccp_v6_send_response(const struct sock *sk, struct request_sock *req)
1898c2ecf20Sopenharmony_ci{
1908c2ecf20Sopenharmony_ci	struct inet_request_sock *ireq = inet_rsk(req);
1918c2ecf20Sopenharmony_ci	struct ipv6_pinfo *np = inet6_sk(sk);
1928c2ecf20Sopenharmony_ci	struct sk_buff *skb;
1938c2ecf20Sopenharmony_ci	struct in6_addr *final_p, final;
1948c2ecf20Sopenharmony_ci	struct flowi6 fl6;
1958c2ecf20Sopenharmony_ci	int err = -1;
1968c2ecf20Sopenharmony_ci	struct dst_entry *dst;
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_ci	memset(&fl6, 0, sizeof(fl6));
1998c2ecf20Sopenharmony_ci	fl6.flowi6_proto = IPPROTO_DCCP;
2008c2ecf20Sopenharmony_ci	fl6.daddr = ireq->ir_v6_rmt_addr;
2018c2ecf20Sopenharmony_ci	fl6.saddr = ireq->ir_v6_loc_addr;
2028c2ecf20Sopenharmony_ci	fl6.flowlabel = 0;
2038c2ecf20Sopenharmony_ci	fl6.flowi6_oif = ireq->ir_iif;
2048c2ecf20Sopenharmony_ci	fl6.fl6_dport = ireq->ir_rmt_port;
2058c2ecf20Sopenharmony_ci	fl6.fl6_sport = htons(ireq->ir_num);
2068c2ecf20Sopenharmony_ci	security_req_classify_flow(req, flowi6_to_flowi_common(&fl6));
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_ci	rcu_read_lock();
2108c2ecf20Sopenharmony_ci	final_p = fl6_update_dst(&fl6, rcu_dereference(np->opt), &final);
2118c2ecf20Sopenharmony_ci	rcu_read_unlock();
2128c2ecf20Sopenharmony_ci
2138c2ecf20Sopenharmony_ci	dst = ip6_dst_lookup_flow(sock_net(sk), sk, &fl6, final_p);
2148c2ecf20Sopenharmony_ci	if (IS_ERR(dst)) {
2158c2ecf20Sopenharmony_ci		err = PTR_ERR(dst);
2168c2ecf20Sopenharmony_ci		dst = NULL;
2178c2ecf20Sopenharmony_ci		goto done;
2188c2ecf20Sopenharmony_ci	}
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_ci	skb = dccp_make_response(sk, dst, req);
2218c2ecf20Sopenharmony_ci	if (skb != NULL) {
2228c2ecf20Sopenharmony_ci		struct dccp_hdr *dh = dccp_hdr(skb);
2238c2ecf20Sopenharmony_ci		struct ipv6_txoptions *opt;
2248c2ecf20Sopenharmony_ci
2258c2ecf20Sopenharmony_ci		dh->dccph_checksum = dccp_v6_csum_finish(skb,
2268c2ecf20Sopenharmony_ci							 &ireq->ir_v6_loc_addr,
2278c2ecf20Sopenharmony_ci							 &ireq->ir_v6_rmt_addr);
2288c2ecf20Sopenharmony_ci		fl6.daddr = ireq->ir_v6_rmt_addr;
2298c2ecf20Sopenharmony_ci		rcu_read_lock();
2308c2ecf20Sopenharmony_ci		opt = ireq->ipv6_opt;
2318c2ecf20Sopenharmony_ci		if (!opt)
2328c2ecf20Sopenharmony_ci			opt = rcu_dereference(np->opt);
2338c2ecf20Sopenharmony_ci		err = ip6_xmit(sk, skb, &fl6, sk->sk_mark, opt, np->tclass,
2348c2ecf20Sopenharmony_ci			       sk->sk_priority);
2358c2ecf20Sopenharmony_ci		rcu_read_unlock();
2368c2ecf20Sopenharmony_ci		err = net_xmit_eval(err);
2378c2ecf20Sopenharmony_ci	}
2388c2ecf20Sopenharmony_ci
2398c2ecf20Sopenharmony_cidone:
2408c2ecf20Sopenharmony_ci	dst_release(dst);
2418c2ecf20Sopenharmony_ci	return err;
2428c2ecf20Sopenharmony_ci}
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_cistatic void dccp_v6_reqsk_destructor(struct request_sock *req)
2458c2ecf20Sopenharmony_ci{
2468c2ecf20Sopenharmony_ci	dccp_feat_list_purge(&dccp_rsk(req)->dreq_featneg);
2478c2ecf20Sopenharmony_ci	kfree(inet_rsk(req)->ipv6_opt);
2488c2ecf20Sopenharmony_ci	kfree_skb(inet_rsk(req)->pktopts);
2498c2ecf20Sopenharmony_ci}
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_cistatic void dccp_v6_ctl_send_reset(const struct sock *sk, struct sk_buff *rxskb)
2528c2ecf20Sopenharmony_ci{
2538c2ecf20Sopenharmony_ci	const struct ipv6hdr *rxip6h;
2548c2ecf20Sopenharmony_ci	struct sk_buff *skb;
2558c2ecf20Sopenharmony_ci	struct flowi6 fl6;
2568c2ecf20Sopenharmony_ci	struct net *net = dev_net(skb_dst(rxskb)->dev);
2578c2ecf20Sopenharmony_ci	struct sock *ctl_sk = net->dccp.v6_ctl_sk;
2588c2ecf20Sopenharmony_ci	struct dst_entry *dst;
2598c2ecf20Sopenharmony_ci
2608c2ecf20Sopenharmony_ci	if (dccp_hdr(rxskb)->dccph_type == DCCP_PKT_RESET)
2618c2ecf20Sopenharmony_ci		return;
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_ci	if (!ipv6_unicast_destination(rxskb))
2648c2ecf20Sopenharmony_ci		return;
2658c2ecf20Sopenharmony_ci
2668c2ecf20Sopenharmony_ci	skb = dccp_ctl_make_reset(ctl_sk, rxskb);
2678c2ecf20Sopenharmony_ci	if (skb == NULL)
2688c2ecf20Sopenharmony_ci		return;
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_ci	rxip6h = ipv6_hdr(rxskb);
2718c2ecf20Sopenharmony_ci	dccp_hdr(skb)->dccph_checksum = dccp_v6_csum_finish(skb, &rxip6h->saddr,
2728c2ecf20Sopenharmony_ci							    &rxip6h->daddr);
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_ci	memset(&fl6, 0, sizeof(fl6));
2758c2ecf20Sopenharmony_ci	fl6.daddr = rxip6h->saddr;
2768c2ecf20Sopenharmony_ci	fl6.saddr = rxip6h->daddr;
2778c2ecf20Sopenharmony_ci
2788c2ecf20Sopenharmony_ci	fl6.flowi6_proto = IPPROTO_DCCP;
2798c2ecf20Sopenharmony_ci	fl6.flowi6_oif = inet6_iif(rxskb);
2808c2ecf20Sopenharmony_ci	fl6.fl6_dport = dccp_hdr(skb)->dccph_dport;
2818c2ecf20Sopenharmony_ci	fl6.fl6_sport = dccp_hdr(skb)->dccph_sport;
2828c2ecf20Sopenharmony_ci	security_skb_classify_flow(rxskb, flowi6_to_flowi_common(&fl6));
2838c2ecf20Sopenharmony_ci
2848c2ecf20Sopenharmony_ci	/* sk = NULL, but it is safe for now. RST socket required. */
2858c2ecf20Sopenharmony_ci	dst = ip6_dst_lookup_flow(sock_net(ctl_sk), ctl_sk, &fl6, NULL);
2868c2ecf20Sopenharmony_ci	if (!IS_ERR(dst)) {
2878c2ecf20Sopenharmony_ci		skb_dst_set(skb, dst);
2888c2ecf20Sopenharmony_ci		ip6_xmit(ctl_sk, skb, &fl6, 0, NULL, 0, 0);
2898c2ecf20Sopenharmony_ci		DCCP_INC_STATS(DCCP_MIB_OUTSEGS);
2908c2ecf20Sopenharmony_ci		DCCP_INC_STATS(DCCP_MIB_OUTRSTS);
2918c2ecf20Sopenharmony_ci		return;
2928c2ecf20Sopenharmony_ci	}
2938c2ecf20Sopenharmony_ci
2948c2ecf20Sopenharmony_ci	kfree_skb(skb);
2958c2ecf20Sopenharmony_ci}
2968c2ecf20Sopenharmony_ci
2978c2ecf20Sopenharmony_cistatic struct request_sock_ops dccp6_request_sock_ops = {
2988c2ecf20Sopenharmony_ci	.family		= AF_INET6,
2998c2ecf20Sopenharmony_ci	.obj_size	= sizeof(struct dccp6_request_sock),
3008c2ecf20Sopenharmony_ci	.rtx_syn_ack	= dccp_v6_send_response,
3018c2ecf20Sopenharmony_ci	.send_ack	= dccp_reqsk_send_ack,
3028c2ecf20Sopenharmony_ci	.destructor	= dccp_v6_reqsk_destructor,
3038c2ecf20Sopenharmony_ci	.send_reset	= dccp_v6_ctl_send_reset,
3048c2ecf20Sopenharmony_ci	.syn_ack_timeout = dccp_syn_ack_timeout,
3058c2ecf20Sopenharmony_ci};
3068c2ecf20Sopenharmony_ci
3078c2ecf20Sopenharmony_cistatic int dccp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
3088c2ecf20Sopenharmony_ci{
3098c2ecf20Sopenharmony_ci	struct request_sock *req;
3108c2ecf20Sopenharmony_ci	struct dccp_request_sock *dreq;
3118c2ecf20Sopenharmony_ci	struct inet_request_sock *ireq;
3128c2ecf20Sopenharmony_ci	struct ipv6_pinfo *np = inet6_sk(sk);
3138c2ecf20Sopenharmony_ci	const __be32 service = dccp_hdr_request(skb)->dccph_req_service;
3148c2ecf20Sopenharmony_ci	struct dccp_skb_cb *dcb = DCCP_SKB_CB(skb);
3158c2ecf20Sopenharmony_ci
3168c2ecf20Sopenharmony_ci	if (skb->protocol == htons(ETH_P_IP))
3178c2ecf20Sopenharmony_ci		return dccp_v4_conn_request(sk, skb);
3188c2ecf20Sopenharmony_ci
3198c2ecf20Sopenharmony_ci	if (!ipv6_unicast_destination(skb))
3208c2ecf20Sopenharmony_ci		return 0;	/* discard, don't send a reset here */
3218c2ecf20Sopenharmony_ci
3228c2ecf20Sopenharmony_ci	if (ipv6_addr_v4mapped(&ipv6_hdr(skb)->saddr)) {
3238c2ecf20Sopenharmony_ci		__IP6_INC_STATS(sock_net(sk), NULL, IPSTATS_MIB_INHDRERRORS);
3248c2ecf20Sopenharmony_ci		return 0;
3258c2ecf20Sopenharmony_ci	}
3268c2ecf20Sopenharmony_ci
3278c2ecf20Sopenharmony_ci	if (dccp_bad_service_code(sk, service)) {
3288c2ecf20Sopenharmony_ci		dcb->dccpd_reset_code = DCCP_RESET_CODE_BAD_SERVICE_CODE;
3298c2ecf20Sopenharmony_ci		goto drop;
3308c2ecf20Sopenharmony_ci	}
3318c2ecf20Sopenharmony_ci	/*
3328c2ecf20Sopenharmony_ci	 * There are no SYN attacks on IPv6, yet...
3338c2ecf20Sopenharmony_ci	 */
3348c2ecf20Sopenharmony_ci	dcb->dccpd_reset_code = DCCP_RESET_CODE_TOO_BUSY;
3358c2ecf20Sopenharmony_ci	if (inet_csk_reqsk_queue_is_full(sk))
3368c2ecf20Sopenharmony_ci		goto drop;
3378c2ecf20Sopenharmony_ci
3388c2ecf20Sopenharmony_ci	if (sk_acceptq_is_full(sk))
3398c2ecf20Sopenharmony_ci		goto drop;
3408c2ecf20Sopenharmony_ci
3418c2ecf20Sopenharmony_ci	req = inet_reqsk_alloc(&dccp6_request_sock_ops, sk, true);
3428c2ecf20Sopenharmony_ci	if (req == NULL)
3438c2ecf20Sopenharmony_ci		goto drop;
3448c2ecf20Sopenharmony_ci
3458c2ecf20Sopenharmony_ci	if (dccp_reqsk_init(req, dccp_sk(sk), skb))
3468c2ecf20Sopenharmony_ci		goto drop_and_free;
3478c2ecf20Sopenharmony_ci
3488c2ecf20Sopenharmony_ci	dreq = dccp_rsk(req);
3498c2ecf20Sopenharmony_ci	if (dccp_parse_options(sk, dreq, skb))
3508c2ecf20Sopenharmony_ci		goto drop_and_free;
3518c2ecf20Sopenharmony_ci
3528c2ecf20Sopenharmony_ci	ireq = inet_rsk(req);
3538c2ecf20Sopenharmony_ci	ireq->ir_v6_rmt_addr = ipv6_hdr(skb)->saddr;
3548c2ecf20Sopenharmony_ci	ireq->ir_v6_loc_addr = ipv6_hdr(skb)->daddr;
3558c2ecf20Sopenharmony_ci	ireq->ireq_family = AF_INET6;
3568c2ecf20Sopenharmony_ci	ireq->ir_mark = inet_request_mark(sk, skb);
3578c2ecf20Sopenharmony_ci
3588c2ecf20Sopenharmony_ci	if (security_inet_conn_request(sk, skb, req))
3598c2ecf20Sopenharmony_ci		goto drop_and_free;
3608c2ecf20Sopenharmony_ci
3618c2ecf20Sopenharmony_ci	if (ipv6_opt_accepted(sk, skb, IP6CB(skb)) ||
3628c2ecf20Sopenharmony_ci	    np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo ||
3638c2ecf20Sopenharmony_ci	    np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim) {
3648c2ecf20Sopenharmony_ci		refcount_inc(&skb->users);
3658c2ecf20Sopenharmony_ci		ireq->pktopts = skb;
3668c2ecf20Sopenharmony_ci	}
3678c2ecf20Sopenharmony_ci	ireq->ir_iif = sk->sk_bound_dev_if;
3688c2ecf20Sopenharmony_ci
3698c2ecf20Sopenharmony_ci	/* So that link locals have meaning */
3708c2ecf20Sopenharmony_ci	if (!sk->sk_bound_dev_if &&
3718c2ecf20Sopenharmony_ci	    ipv6_addr_type(&ireq->ir_v6_rmt_addr) & IPV6_ADDR_LINKLOCAL)
3728c2ecf20Sopenharmony_ci		ireq->ir_iif = inet6_iif(skb);
3738c2ecf20Sopenharmony_ci
3748c2ecf20Sopenharmony_ci	/*
3758c2ecf20Sopenharmony_ci	 * Step 3: Process LISTEN state
3768c2ecf20Sopenharmony_ci	 *
3778c2ecf20Sopenharmony_ci	 *   Set S.ISR, S.GSR, S.SWL, S.SWH from packet or Init Cookie
3788c2ecf20Sopenharmony_ci	 *
3798c2ecf20Sopenharmony_ci	 * Setting S.SWL/S.SWH to is deferred to dccp_create_openreq_child().
3808c2ecf20Sopenharmony_ci	 */
3818c2ecf20Sopenharmony_ci	dreq->dreq_isr	   = dcb->dccpd_seq;
3828c2ecf20Sopenharmony_ci	dreq->dreq_gsr     = dreq->dreq_isr;
3838c2ecf20Sopenharmony_ci	dreq->dreq_iss	   = dccp_v6_init_sequence(skb);
3848c2ecf20Sopenharmony_ci	dreq->dreq_gss     = dreq->dreq_iss;
3858c2ecf20Sopenharmony_ci	dreq->dreq_service = service;
3868c2ecf20Sopenharmony_ci
3878c2ecf20Sopenharmony_ci	if (dccp_v6_send_response(sk, req))
3888c2ecf20Sopenharmony_ci		goto drop_and_free;
3898c2ecf20Sopenharmony_ci
3908c2ecf20Sopenharmony_ci	inet_csk_reqsk_queue_hash_add(sk, req, DCCP_TIMEOUT_INIT);
3918c2ecf20Sopenharmony_ci	reqsk_put(req);
3928c2ecf20Sopenharmony_ci	return 0;
3938c2ecf20Sopenharmony_ci
3948c2ecf20Sopenharmony_cidrop_and_free:
3958c2ecf20Sopenharmony_ci	reqsk_free(req);
3968c2ecf20Sopenharmony_cidrop:
3978c2ecf20Sopenharmony_ci	__DCCP_INC_STATS(DCCP_MIB_ATTEMPTFAILS);
3988c2ecf20Sopenharmony_ci	return -1;
3998c2ecf20Sopenharmony_ci}
4008c2ecf20Sopenharmony_ci
4018c2ecf20Sopenharmony_cistatic struct sock *dccp_v6_request_recv_sock(const struct sock *sk,
4028c2ecf20Sopenharmony_ci					      struct sk_buff *skb,
4038c2ecf20Sopenharmony_ci					      struct request_sock *req,
4048c2ecf20Sopenharmony_ci					      struct dst_entry *dst,
4058c2ecf20Sopenharmony_ci					      struct request_sock *req_unhash,
4068c2ecf20Sopenharmony_ci					      bool *own_req)
4078c2ecf20Sopenharmony_ci{
4088c2ecf20Sopenharmony_ci	struct inet_request_sock *ireq = inet_rsk(req);
4098c2ecf20Sopenharmony_ci	struct ipv6_pinfo *newnp;
4108c2ecf20Sopenharmony_ci	const struct ipv6_pinfo *np = inet6_sk(sk);
4118c2ecf20Sopenharmony_ci	struct ipv6_txoptions *opt;
4128c2ecf20Sopenharmony_ci	struct inet_sock *newinet;
4138c2ecf20Sopenharmony_ci	struct dccp6_sock *newdp6;
4148c2ecf20Sopenharmony_ci	struct sock *newsk;
4158c2ecf20Sopenharmony_ci
4168c2ecf20Sopenharmony_ci	if (skb->protocol == htons(ETH_P_IP)) {
4178c2ecf20Sopenharmony_ci		/*
4188c2ecf20Sopenharmony_ci		 *	v6 mapped
4198c2ecf20Sopenharmony_ci		 */
4208c2ecf20Sopenharmony_ci		newsk = dccp_v4_request_recv_sock(sk, skb, req, dst,
4218c2ecf20Sopenharmony_ci						  req_unhash, own_req);
4228c2ecf20Sopenharmony_ci		if (newsk == NULL)
4238c2ecf20Sopenharmony_ci			return NULL;
4248c2ecf20Sopenharmony_ci
4258c2ecf20Sopenharmony_ci		newdp6 = (struct dccp6_sock *)newsk;
4268c2ecf20Sopenharmony_ci		newinet = inet_sk(newsk);
4278c2ecf20Sopenharmony_ci		newinet->pinet6 = &newdp6->inet6;
4288c2ecf20Sopenharmony_ci		newnp = inet6_sk(newsk);
4298c2ecf20Sopenharmony_ci
4308c2ecf20Sopenharmony_ci		memcpy(newnp, np, sizeof(struct ipv6_pinfo));
4318c2ecf20Sopenharmony_ci
4328c2ecf20Sopenharmony_ci		newnp->saddr = newsk->sk_v6_rcv_saddr;
4338c2ecf20Sopenharmony_ci
4348c2ecf20Sopenharmony_ci		inet_csk(newsk)->icsk_af_ops = &dccp_ipv6_mapped;
4358c2ecf20Sopenharmony_ci		newsk->sk_backlog_rcv = dccp_v4_do_rcv;
4368c2ecf20Sopenharmony_ci		newnp->pktoptions  = NULL;
4378c2ecf20Sopenharmony_ci		newnp->opt	   = NULL;
4388c2ecf20Sopenharmony_ci		newnp->ipv6_mc_list = NULL;
4398c2ecf20Sopenharmony_ci		newnp->ipv6_ac_list = NULL;
4408c2ecf20Sopenharmony_ci		newnp->ipv6_fl_list = NULL;
4418c2ecf20Sopenharmony_ci		newnp->mcast_oif   = inet_iif(skb);
4428c2ecf20Sopenharmony_ci		newnp->mcast_hops  = ip_hdr(skb)->ttl;
4438c2ecf20Sopenharmony_ci
4448c2ecf20Sopenharmony_ci		/*
4458c2ecf20Sopenharmony_ci		 * No need to charge this sock to the relevant IPv6 refcnt debug socks count
4468c2ecf20Sopenharmony_ci		 * here, dccp_create_openreq_child now does this for us, see the comment in
4478c2ecf20Sopenharmony_ci		 * that function for the gory details. -acme
4488c2ecf20Sopenharmony_ci		 */
4498c2ecf20Sopenharmony_ci
4508c2ecf20Sopenharmony_ci		/* It is tricky place. Until this moment IPv4 tcp
4518c2ecf20Sopenharmony_ci		   worked with IPv6 icsk.icsk_af_ops.
4528c2ecf20Sopenharmony_ci		   Sync it now.
4538c2ecf20Sopenharmony_ci		 */
4548c2ecf20Sopenharmony_ci		dccp_sync_mss(newsk, inet_csk(newsk)->icsk_pmtu_cookie);
4558c2ecf20Sopenharmony_ci
4568c2ecf20Sopenharmony_ci		return newsk;
4578c2ecf20Sopenharmony_ci	}
4588c2ecf20Sopenharmony_ci
4598c2ecf20Sopenharmony_ci
4608c2ecf20Sopenharmony_ci	if (sk_acceptq_is_full(sk))
4618c2ecf20Sopenharmony_ci		goto out_overflow;
4628c2ecf20Sopenharmony_ci
4638c2ecf20Sopenharmony_ci	if (!dst) {
4648c2ecf20Sopenharmony_ci		struct flowi6 fl6;
4658c2ecf20Sopenharmony_ci
4668c2ecf20Sopenharmony_ci		dst = inet6_csk_route_req(sk, &fl6, req, IPPROTO_DCCP);
4678c2ecf20Sopenharmony_ci		if (!dst)
4688c2ecf20Sopenharmony_ci			goto out;
4698c2ecf20Sopenharmony_ci	}
4708c2ecf20Sopenharmony_ci
4718c2ecf20Sopenharmony_ci	newsk = dccp_create_openreq_child(sk, req, skb);
4728c2ecf20Sopenharmony_ci	if (newsk == NULL)
4738c2ecf20Sopenharmony_ci		goto out_nonewsk;
4748c2ecf20Sopenharmony_ci
4758c2ecf20Sopenharmony_ci	/*
4768c2ecf20Sopenharmony_ci	 * No need to charge this sock to the relevant IPv6 refcnt debug socks
4778c2ecf20Sopenharmony_ci	 * count here, dccp_create_openreq_child now does this for us, see the
4788c2ecf20Sopenharmony_ci	 * comment in that function for the gory details. -acme
4798c2ecf20Sopenharmony_ci	 */
4808c2ecf20Sopenharmony_ci
4818c2ecf20Sopenharmony_ci	ip6_dst_store(newsk, dst, NULL, NULL);
4828c2ecf20Sopenharmony_ci	newsk->sk_route_caps = dst->dev->features & ~(NETIF_F_IP_CSUM |
4838c2ecf20Sopenharmony_ci						      NETIF_F_TSO);
4848c2ecf20Sopenharmony_ci	newdp6 = (struct dccp6_sock *)newsk;
4858c2ecf20Sopenharmony_ci	newinet = inet_sk(newsk);
4868c2ecf20Sopenharmony_ci	newinet->pinet6 = &newdp6->inet6;
4878c2ecf20Sopenharmony_ci	newnp = inet6_sk(newsk);
4888c2ecf20Sopenharmony_ci
4898c2ecf20Sopenharmony_ci	memcpy(newnp, np, sizeof(struct ipv6_pinfo));
4908c2ecf20Sopenharmony_ci
4918c2ecf20Sopenharmony_ci	newsk->sk_v6_daddr	= ireq->ir_v6_rmt_addr;
4928c2ecf20Sopenharmony_ci	newnp->saddr		= ireq->ir_v6_loc_addr;
4938c2ecf20Sopenharmony_ci	newsk->sk_v6_rcv_saddr	= ireq->ir_v6_loc_addr;
4948c2ecf20Sopenharmony_ci	newsk->sk_bound_dev_if	= ireq->ir_iif;
4958c2ecf20Sopenharmony_ci
4968c2ecf20Sopenharmony_ci	/* Now IPv6 options...
4978c2ecf20Sopenharmony_ci
4988c2ecf20Sopenharmony_ci	   First: no IPv4 options.
4998c2ecf20Sopenharmony_ci	 */
5008c2ecf20Sopenharmony_ci	newinet->inet_opt = NULL;
5018c2ecf20Sopenharmony_ci
5028c2ecf20Sopenharmony_ci	/* Clone RX bits */
5038c2ecf20Sopenharmony_ci	newnp->rxopt.all = np->rxopt.all;
5048c2ecf20Sopenharmony_ci
5058c2ecf20Sopenharmony_ci	newnp->ipv6_mc_list = NULL;
5068c2ecf20Sopenharmony_ci	newnp->ipv6_ac_list = NULL;
5078c2ecf20Sopenharmony_ci	newnp->ipv6_fl_list = NULL;
5088c2ecf20Sopenharmony_ci	newnp->pktoptions = NULL;
5098c2ecf20Sopenharmony_ci	newnp->opt	  = NULL;
5108c2ecf20Sopenharmony_ci	newnp->mcast_oif  = inet6_iif(skb);
5118c2ecf20Sopenharmony_ci	newnp->mcast_hops = ipv6_hdr(skb)->hop_limit;
5128c2ecf20Sopenharmony_ci
5138c2ecf20Sopenharmony_ci	/*
5148c2ecf20Sopenharmony_ci	 * Clone native IPv6 options from listening socket (if any)
5158c2ecf20Sopenharmony_ci	 *
5168c2ecf20Sopenharmony_ci	 * Yes, keeping reference count would be much more clever, but we make
5178c2ecf20Sopenharmony_ci	 * one more one thing there: reattach optmem to newsk.
5188c2ecf20Sopenharmony_ci	 */
5198c2ecf20Sopenharmony_ci	opt = ireq->ipv6_opt;
5208c2ecf20Sopenharmony_ci	if (!opt)
5218c2ecf20Sopenharmony_ci		opt = rcu_dereference(np->opt);
5228c2ecf20Sopenharmony_ci	if (opt) {
5238c2ecf20Sopenharmony_ci		opt = ipv6_dup_options(newsk, opt);
5248c2ecf20Sopenharmony_ci		RCU_INIT_POINTER(newnp->opt, opt);
5258c2ecf20Sopenharmony_ci	}
5268c2ecf20Sopenharmony_ci	inet_csk(newsk)->icsk_ext_hdr_len = 0;
5278c2ecf20Sopenharmony_ci	if (opt)
5288c2ecf20Sopenharmony_ci		inet_csk(newsk)->icsk_ext_hdr_len = opt->opt_nflen +
5298c2ecf20Sopenharmony_ci						    opt->opt_flen;
5308c2ecf20Sopenharmony_ci
5318c2ecf20Sopenharmony_ci	dccp_sync_mss(newsk, dst_mtu(dst));
5328c2ecf20Sopenharmony_ci
5338c2ecf20Sopenharmony_ci	newinet->inet_daddr = newinet->inet_saddr = LOOPBACK4_IPV6;
5348c2ecf20Sopenharmony_ci	newinet->inet_rcv_saddr = LOOPBACK4_IPV6;
5358c2ecf20Sopenharmony_ci
5368c2ecf20Sopenharmony_ci	if (__inet_inherit_port(sk, newsk) < 0) {
5378c2ecf20Sopenharmony_ci		inet_csk_prepare_forced_close(newsk);
5388c2ecf20Sopenharmony_ci		dccp_done(newsk);
5398c2ecf20Sopenharmony_ci		goto out;
5408c2ecf20Sopenharmony_ci	}
5418c2ecf20Sopenharmony_ci	*own_req = inet_ehash_nolisten(newsk, req_to_sk(req_unhash), NULL);
5428c2ecf20Sopenharmony_ci	/* Clone pktoptions received with SYN, if we own the req */
5438c2ecf20Sopenharmony_ci	if (*own_req && ireq->pktopts) {
5448c2ecf20Sopenharmony_ci		newnp->pktoptions = skb_clone_and_charge_r(ireq->pktopts, newsk);
5458c2ecf20Sopenharmony_ci		consume_skb(ireq->pktopts);
5468c2ecf20Sopenharmony_ci		ireq->pktopts = NULL;
5478c2ecf20Sopenharmony_ci	}
5488c2ecf20Sopenharmony_ci
5498c2ecf20Sopenharmony_ci	return newsk;
5508c2ecf20Sopenharmony_ci
5518c2ecf20Sopenharmony_ciout_overflow:
5528c2ecf20Sopenharmony_ci	__NET_INC_STATS(sock_net(sk), LINUX_MIB_LISTENOVERFLOWS);
5538c2ecf20Sopenharmony_ciout_nonewsk:
5548c2ecf20Sopenharmony_ci	dst_release(dst);
5558c2ecf20Sopenharmony_ciout:
5568c2ecf20Sopenharmony_ci	__NET_INC_STATS(sock_net(sk), LINUX_MIB_LISTENDROPS);
5578c2ecf20Sopenharmony_ci	return NULL;
5588c2ecf20Sopenharmony_ci}
5598c2ecf20Sopenharmony_ci
5608c2ecf20Sopenharmony_ci/* The socket must have it's spinlock held when we get
5618c2ecf20Sopenharmony_ci * here.
5628c2ecf20Sopenharmony_ci *
5638c2ecf20Sopenharmony_ci * We have a potential double-lock case here, so even when
5648c2ecf20Sopenharmony_ci * doing backlog processing we use the BH locking scheme.
5658c2ecf20Sopenharmony_ci * This is because we cannot sleep with the original spinlock
5668c2ecf20Sopenharmony_ci * held.
5678c2ecf20Sopenharmony_ci */
5688c2ecf20Sopenharmony_cistatic int dccp_v6_do_rcv(struct sock *sk, struct sk_buff *skb)
5698c2ecf20Sopenharmony_ci{
5708c2ecf20Sopenharmony_ci	struct ipv6_pinfo *np = inet6_sk(sk);
5718c2ecf20Sopenharmony_ci	struct sk_buff *opt_skb = NULL;
5728c2ecf20Sopenharmony_ci
5738c2ecf20Sopenharmony_ci	/* Imagine: socket is IPv6. IPv4 packet arrives,
5748c2ecf20Sopenharmony_ci	   goes to IPv4 receive handler and backlogged.
5758c2ecf20Sopenharmony_ci	   From backlog it always goes here. Kerboom...
5768c2ecf20Sopenharmony_ci	   Fortunately, dccp_rcv_established and rcv_established
5778c2ecf20Sopenharmony_ci	   handle them correctly, but it is not case with
5788c2ecf20Sopenharmony_ci	   dccp_v6_hnd_req and dccp_v6_ctl_send_reset().   --ANK
5798c2ecf20Sopenharmony_ci	 */
5808c2ecf20Sopenharmony_ci
5818c2ecf20Sopenharmony_ci	if (skb->protocol == htons(ETH_P_IP))
5828c2ecf20Sopenharmony_ci		return dccp_v4_do_rcv(sk, skb);
5838c2ecf20Sopenharmony_ci
5848c2ecf20Sopenharmony_ci	if (sk_filter(sk, skb))
5858c2ecf20Sopenharmony_ci		goto discard;
5868c2ecf20Sopenharmony_ci
5878c2ecf20Sopenharmony_ci	/*
5888c2ecf20Sopenharmony_ci	 * socket locking is here for SMP purposes as backlog rcv is currently
5898c2ecf20Sopenharmony_ci	 * called with bh processing disabled.
5908c2ecf20Sopenharmony_ci	 */
5918c2ecf20Sopenharmony_ci
5928c2ecf20Sopenharmony_ci	/* Do Stevens' IPV6_PKTOPTIONS.
5938c2ecf20Sopenharmony_ci
5948c2ecf20Sopenharmony_ci	   Yes, guys, it is the only place in our code, where we
5958c2ecf20Sopenharmony_ci	   may make it not affecting IPv4.
5968c2ecf20Sopenharmony_ci	   The rest of code is protocol independent,
5978c2ecf20Sopenharmony_ci	   and I do not like idea to uglify IPv4.
5988c2ecf20Sopenharmony_ci
5998c2ecf20Sopenharmony_ci	   Actually, all the idea behind IPV6_PKTOPTIONS
6008c2ecf20Sopenharmony_ci	   looks not very well thought. For now we latch
6018c2ecf20Sopenharmony_ci	   options, received in the last packet, enqueued
6028c2ecf20Sopenharmony_ci	   by tcp. Feel free to propose better solution.
6038c2ecf20Sopenharmony_ci					       --ANK (980728)
6048c2ecf20Sopenharmony_ci	 */
6058c2ecf20Sopenharmony_ci	if (np->rxopt.all)
6068c2ecf20Sopenharmony_ci		opt_skb = skb_clone_and_charge_r(skb, sk);
6078c2ecf20Sopenharmony_ci
6088c2ecf20Sopenharmony_ci	if (sk->sk_state == DCCP_OPEN) { /* Fast path */
6098c2ecf20Sopenharmony_ci		if (dccp_rcv_established(sk, skb, dccp_hdr(skb), skb->len))
6108c2ecf20Sopenharmony_ci			goto reset;
6118c2ecf20Sopenharmony_ci		if (opt_skb)
6128c2ecf20Sopenharmony_ci			goto ipv6_pktoptions;
6138c2ecf20Sopenharmony_ci		return 0;
6148c2ecf20Sopenharmony_ci	}
6158c2ecf20Sopenharmony_ci
6168c2ecf20Sopenharmony_ci	/*
6178c2ecf20Sopenharmony_ci	 *  Step 3: Process LISTEN state
6188c2ecf20Sopenharmony_ci	 *     If S.state == LISTEN,
6198c2ecf20Sopenharmony_ci	 *	 If P.type == Request or P contains a valid Init Cookie option,
6208c2ecf20Sopenharmony_ci	 *	      (* Must scan the packet's options to check for Init
6218c2ecf20Sopenharmony_ci	 *		 Cookies.  Only Init Cookies are processed here,
6228c2ecf20Sopenharmony_ci	 *		 however; other options are processed in Step 8.  This
6238c2ecf20Sopenharmony_ci	 *		 scan need only be performed if the endpoint uses Init
6248c2ecf20Sopenharmony_ci	 *		 Cookies *)
6258c2ecf20Sopenharmony_ci	 *	      (* Generate a new socket and switch to that socket *)
6268c2ecf20Sopenharmony_ci	 *	      Set S := new socket for this port pair
6278c2ecf20Sopenharmony_ci	 *	      S.state = RESPOND
6288c2ecf20Sopenharmony_ci	 *	      Choose S.ISS (initial seqno) or set from Init Cookies
6298c2ecf20Sopenharmony_ci	 *	      Initialize S.GAR := S.ISS
6308c2ecf20Sopenharmony_ci	 *	      Set S.ISR, S.GSR, S.SWL, S.SWH from packet or Init Cookies
6318c2ecf20Sopenharmony_ci	 *	      Continue with S.state == RESPOND
6328c2ecf20Sopenharmony_ci	 *	      (* A Response packet will be generated in Step 11 *)
6338c2ecf20Sopenharmony_ci	 *	 Otherwise,
6348c2ecf20Sopenharmony_ci	 *	      Generate Reset(No Connection) unless P.type == Reset
6358c2ecf20Sopenharmony_ci	 *	      Drop packet and return
6368c2ecf20Sopenharmony_ci	 *
6378c2ecf20Sopenharmony_ci	 * NOTE: the check for the packet types is done in
6388c2ecf20Sopenharmony_ci	 *	 dccp_rcv_state_process
6398c2ecf20Sopenharmony_ci	 */
6408c2ecf20Sopenharmony_ci
6418c2ecf20Sopenharmony_ci	if (dccp_rcv_state_process(sk, skb, dccp_hdr(skb), skb->len))
6428c2ecf20Sopenharmony_ci		goto reset;
6438c2ecf20Sopenharmony_ci	if (opt_skb)
6448c2ecf20Sopenharmony_ci		goto ipv6_pktoptions;
6458c2ecf20Sopenharmony_ci	return 0;
6468c2ecf20Sopenharmony_ci
6478c2ecf20Sopenharmony_cireset:
6488c2ecf20Sopenharmony_ci	dccp_v6_ctl_send_reset(sk, skb);
6498c2ecf20Sopenharmony_cidiscard:
6508c2ecf20Sopenharmony_ci	if (opt_skb != NULL)
6518c2ecf20Sopenharmony_ci		__kfree_skb(opt_skb);
6528c2ecf20Sopenharmony_ci	kfree_skb(skb);
6538c2ecf20Sopenharmony_ci	return 0;
6548c2ecf20Sopenharmony_ci
6558c2ecf20Sopenharmony_ci/* Handling IPV6_PKTOPTIONS skb the similar
6568c2ecf20Sopenharmony_ci * way it's done for net/ipv6/tcp_ipv6.c
6578c2ecf20Sopenharmony_ci */
6588c2ecf20Sopenharmony_ciipv6_pktoptions:
6598c2ecf20Sopenharmony_ci	if (!((1 << sk->sk_state) & (DCCPF_CLOSED | DCCPF_LISTEN))) {
6608c2ecf20Sopenharmony_ci		if (np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo)
6618c2ecf20Sopenharmony_ci			np->mcast_oif = inet6_iif(opt_skb);
6628c2ecf20Sopenharmony_ci		if (np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim)
6638c2ecf20Sopenharmony_ci			np->mcast_hops = ipv6_hdr(opt_skb)->hop_limit;
6648c2ecf20Sopenharmony_ci		if (np->rxopt.bits.rxflow || np->rxopt.bits.rxtclass)
6658c2ecf20Sopenharmony_ci			np->rcv_flowinfo = ip6_flowinfo(ipv6_hdr(opt_skb));
6668c2ecf20Sopenharmony_ci		if (np->repflow)
6678c2ecf20Sopenharmony_ci			np->flow_label = ip6_flowlabel(ipv6_hdr(opt_skb));
6688c2ecf20Sopenharmony_ci		if (ipv6_opt_accepted(sk, opt_skb,
6698c2ecf20Sopenharmony_ci				      &DCCP_SKB_CB(opt_skb)->header.h6)) {
6708c2ecf20Sopenharmony_ci			memmove(IP6CB(opt_skb),
6718c2ecf20Sopenharmony_ci				&DCCP_SKB_CB(opt_skb)->header.h6,
6728c2ecf20Sopenharmony_ci				sizeof(struct inet6_skb_parm));
6738c2ecf20Sopenharmony_ci			opt_skb = xchg(&np->pktoptions, opt_skb);
6748c2ecf20Sopenharmony_ci		} else {
6758c2ecf20Sopenharmony_ci			__kfree_skb(opt_skb);
6768c2ecf20Sopenharmony_ci			opt_skb = xchg(&np->pktoptions, NULL);
6778c2ecf20Sopenharmony_ci		}
6788c2ecf20Sopenharmony_ci	}
6798c2ecf20Sopenharmony_ci
6808c2ecf20Sopenharmony_ci	kfree_skb(opt_skb);
6818c2ecf20Sopenharmony_ci	return 0;
6828c2ecf20Sopenharmony_ci}
6838c2ecf20Sopenharmony_ci
6848c2ecf20Sopenharmony_cistatic int dccp_v6_rcv(struct sk_buff *skb)
6858c2ecf20Sopenharmony_ci{
6868c2ecf20Sopenharmony_ci	const struct dccp_hdr *dh;
6878c2ecf20Sopenharmony_ci	bool refcounted;
6888c2ecf20Sopenharmony_ci	struct sock *sk;
6898c2ecf20Sopenharmony_ci	int min_cov;
6908c2ecf20Sopenharmony_ci
6918c2ecf20Sopenharmony_ci	/* Step 1: Check header basics */
6928c2ecf20Sopenharmony_ci
6938c2ecf20Sopenharmony_ci	if (dccp_invalid_packet(skb))
6948c2ecf20Sopenharmony_ci		goto discard_it;
6958c2ecf20Sopenharmony_ci
6968c2ecf20Sopenharmony_ci	/* Step 1: If header checksum is incorrect, drop packet and return. */
6978c2ecf20Sopenharmony_ci	if (dccp_v6_csum_finish(skb, &ipv6_hdr(skb)->saddr,
6988c2ecf20Sopenharmony_ci				     &ipv6_hdr(skb)->daddr)) {
6998c2ecf20Sopenharmony_ci		DCCP_WARN("dropped packet with invalid checksum\n");
7008c2ecf20Sopenharmony_ci		goto discard_it;
7018c2ecf20Sopenharmony_ci	}
7028c2ecf20Sopenharmony_ci
7038c2ecf20Sopenharmony_ci	dh = dccp_hdr(skb);
7048c2ecf20Sopenharmony_ci
7058c2ecf20Sopenharmony_ci	DCCP_SKB_CB(skb)->dccpd_seq  = dccp_hdr_seq(dh);
7068c2ecf20Sopenharmony_ci	DCCP_SKB_CB(skb)->dccpd_type = dh->dccph_type;
7078c2ecf20Sopenharmony_ci
7088c2ecf20Sopenharmony_ci	if (dccp_packet_without_ack(skb))
7098c2ecf20Sopenharmony_ci		DCCP_SKB_CB(skb)->dccpd_ack_seq = DCCP_PKT_WITHOUT_ACK_SEQ;
7108c2ecf20Sopenharmony_ci	else
7118c2ecf20Sopenharmony_ci		DCCP_SKB_CB(skb)->dccpd_ack_seq = dccp_hdr_ack_seq(skb);
7128c2ecf20Sopenharmony_ci
7138c2ecf20Sopenharmony_cilookup:
7148c2ecf20Sopenharmony_ci	sk = __inet6_lookup_skb(&dccp_hashinfo, skb, __dccp_hdr_len(dh),
7158c2ecf20Sopenharmony_ci			        dh->dccph_sport, dh->dccph_dport,
7168c2ecf20Sopenharmony_ci				inet6_iif(skb), 0, &refcounted);
7178c2ecf20Sopenharmony_ci	if (!sk) {
7188c2ecf20Sopenharmony_ci		dccp_pr_debug("failed to look up flow ID in table and "
7198c2ecf20Sopenharmony_ci			      "get corresponding socket\n");
7208c2ecf20Sopenharmony_ci		goto no_dccp_socket;
7218c2ecf20Sopenharmony_ci	}
7228c2ecf20Sopenharmony_ci
7238c2ecf20Sopenharmony_ci	/*
7248c2ecf20Sopenharmony_ci	 * Step 2:
7258c2ecf20Sopenharmony_ci	 *	... or S.state == TIMEWAIT,
7268c2ecf20Sopenharmony_ci	 *		Generate Reset(No Connection) unless P.type == Reset
7278c2ecf20Sopenharmony_ci	 *		Drop packet and return
7288c2ecf20Sopenharmony_ci	 */
7298c2ecf20Sopenharmony_ci	if (sk->sk_state == DCCP_TIME_WAIT) {
7308c2ecf20Sopenharmony_ci		dccp_pr_debug("sk->sk_state == DCCP_TIME_WAIT: do_time_wait\n");
7318c2ecf20Sopenharmony_ci		inet_twsk_put(inet_twsk(sk));
7328c2ecf20Sopenharmony_ci		goto no_dccp_socket;
7338c2ecf20Sopenharmony_ci	}
7348c2ecf20Sopenharmony_ci
7358c2ecf20Sopenharmony_ci	if (sk->sk_state == DCCP_NEW_SYN_RECV) {
7368c2ecf20Sopenharmony_ci		struct request_sock *req = inet_reqsk(sk);
7378c2ecf20Sopenharmony_ci		struct sock *nsk;
7388c2ecf20Sopenharmony_ci
7398c2ecf20Sopenharmony_ci		sk = req->rsk_listener;
7408c2ecf20Sopenharmony_ci		if (unlikely(sk->sk_state != DCCP_LISTEN)) {
7418c2ecf20Sopenharmony_ci			inet_csk_reqsk_queue_drop_and_put(sk, req);
7428c2ecf20Sopenharmony_ci			goto lookup;
7438c2ecf20Sopenharmony_ci		}
7448c2ecf20Sopenharmony_ci		sock_hold(sk);
7458c2ecf20Sopenharmony_ci		refcounted = true;
7468c2ecf20Sopenharmony_ci		nsk = dccp_check_req(sk, skb, req);
7478c2ecf20Sopenharmony_ci		if (!nsk) {
7488c2ecf20Sopenharmony_ci			reqsk_put(req);
7498c2ecf20Sopenharmony_ci			goto discard_and_relse;
7508c2ecf20Sopenharmony_ci		}
7518c2ecf20Sopenharmony_ci		if (nsk == sk) {
7528c2ecf20Sopenharmony_ci			reqsk_put(req);
7538c2ecf20Sopenharmony_ci		} else if (dccp_child_process(sk, nsk, skb)) {
7548c2ecf20Sopenharmony_ci			dccp_v6_ctl_send_reset(sk, skb);
7558c2ecf20Sopenharmony_ci			goto discard_and_relse;
7568c2ecf20Sopenharmony_ci		} else {
7578c2ecf20Sopenharmony_ci			sock_put(sk);
7588c2ecf20Sopenharmony_ci			return 0;
7598c2ecf20Sopenharmony_ci		}
7608c2ecf20Sopenharmony_ci	}
7618c2ecf20Sopenharmony_ci	/*
7628c2ecf20Sopenharmony_ci	 * RFC 4340, sec. 9.2.1: Minimum Checksum Coverage
7638c2ecf20Sopenharmony_ci	 *	o if MinCsCov = 0, only packets with CsCov = 0 are accepted
7648c2ecf20Sopenharmony_ci	 *	o if MinCsCov > 0, also accept packets with CsCov >= MinCsCov
7658c2ecf20Sopenharmony_ci	 */
7668c2ecf20Sopenharmony_ci	min_cov = dccp_sk(sk)->dccps_pcrlen;
7678c2ecf20Sopenharmony_ci	if (dh->dccph_cscov  &&  (min_cov == 0 || dh->dccph_cscov < min_cov))  {
7688c2ecf20Sopenharmony_ci		dccp_pr_debug("Packet CsCov %d does not satisfy MinCsCov %d\n",
7698c2ecf20Sopenharmony_ci			      dh->dccph_cscov, min_cov);
7708c2ecf20Sopenharmony_ci		/* FIXME: send Data Dropped option (see also dccp_v4_rcv) */
7718c2ecf20Sopenharmony_ci		goto discard_and_relse;
7728c2ecf20Sopenharmony_ci	}
7738c2ecf20Sopenharmony_ci
7748c2ecf20Sopenharmony_ci	if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb))
7758c2ecf20Sopenharmony_ci		goto discard_and_relse;
7768c2ecf20Sopenharmony_ci
7778c2ecf20Sopenharmony_ci	return __sk_receive_skb(sk, skb, 1, dh->dccph_doff * 4,
7788c2ecf20Sopenharmony_ci				refcounted) ? -1 : 0;
7798c2ecf20Sopenharmony_ci
7808c2ecf20Sopenharmony_cino_dccp_socket:
7818c2ecf20Sopenharmony_ci	if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb))
7828c2ecf20Sopenharmony_ci		goto discard_it;
7838c2ecf20Sopenharmony_ci	/*
7848c2ecf20Sopenharmony_ci	 * Step 2:
7858c2ecf20Sopenharmony_ci	 *	If no socket ...
7868c2ecf20Sopenharmony_ci	 *		Generate Reset(No Connection) unless P.type == Reset
7878c2ecf20Sopenharmony_ci	 *		Drop packet and return
7888c2ecf20Sopenharmony_ci	 */
7898c2ecf20Sopenharmony_ci	if (dh->dccph_type != DCCP_PKT_RESET) {
7908c2ecf20Sopenharmony_ci		DCCP_SKB_CB(skb)->dccpd_reset_code =
7918c2ecf20Sopenharmony_ci					DCCP_RESET_CODE_NO_CONNECTION;
7928c2ecf20Sopenharmony_ci		dccp_v6_ctl_send_reset(sk, skb);
7938c2ecf20Sopenharmony_ci	}
7948c2ecf20Sopenharmony_ci
7958c2ecf20Sopenharmony_cidiscard_it:
7968c2ecf20Sopenharmony_ci	kfree_skb(skb);
7978c2ecf20Sopenharmony_ci	return 0;
7988c2ecf20Sopenharmony_ci
7998c2ecf20Sopenharmony_cidiscard_and_relse:
8008c2ecf20Sopenharmony_ci	if (refcounted)
8018c2ecf20Sopenharmony_ci		sock_put(sk);
8028c2ecf20Sopenharmony_ci	goto discard_it;
8038c2ecf20Sopenharmony_ci}
8048c2ecf20Sopenharmony_ci
8058c2ecf20Sopenharmony_cistatic int dccp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
8068c2ecf20Sopenharmony_ci			   int addr_len)
8078c2ecf20Sopenharmony_ci{
8088c2ecf20Sopenharmony_ci	struct sockaddr_in6 *usin = (struct sockaddr_in6 *)uaddr;
8098c2ecf20Sopenharmony_ci	struct inet_connection_sock *icsk = inet_csk(sk);
8108c2ecf20Sopenharmony_ci	struct inet_sock *inet = inet_sk(sk);
8118c2ecf20Sopenharmony_ci	struct ipv6_pinfo *np = inet6_sk(sk);
8128c2ecf20Sopenharmony_ci	struct dccp_sock *dp = dccp_sk(sk);
8138c2ecf20Sopenharmony_ci	struct in6_addr *saddr = NULL, *final_p, final;
8148c2ecf20Sopenharmony_ci	struct ipv6_txoptions *opt;
8158c2ecf20Sopenharmony_ci	struct flowi6 fl6;
8168c2ecf20Sopenharmony_ci	struct dst_entry *dst;
8178c2ecf20Sopenharmony_ci	int addr_type;
8188c2ecf20Sopenharmony_ci	int err;
8198c2ecf20Sopenharmony_ci
8208c2ecf20Sopenharmony_ci	dp->dccps_role = DCCP_ROLE_CLIENT;
8218c2ecf20Sopenharmony_ci
8228c2ecf20Sopenharmony_ci	if (addr_len < SIN6_LEN_RFC2133)
8238c2ecf20Sopenharmony_ci		return -EINVAL;
8248c2ecf20Sopenharmony_ci
8258c2ecf20Sopenharmony_ci	if (usin->sin6_family != AF_INET6)
8268c2ecf20Sopenharmony_ci		return -EAFNOSUPPORT;
8278c2ecf20Sopenharmony_ci
8288c2ecf20Sopenharmony_ci	memset(&fl6, 0, sizeof(fl6));
8298c2ecf20Sopenharmony_ci
8308c2ecf20Sopenharmony_ci	if (np->sndflow) {
8318c2ecf20Sopenharmony_ci		fl6.flowlabel = usin->sin6_flowinfo & IPV6_FLOWINFO_MASK;
8328c2ecf20Sopenharmony_ci		IP6_ECN_flow_init(fl6.flowlabel);
8338c2ecf20Sopenharmony_ci		if (fl6.flowlabel & IPV6_FLOWLABEL_MASK) {
8348c2ecf20Sopenharmony_ci			struct ip6_flowlabel *flowlabel;
8358c2ecf20Sopenharmony_ci			flowlabel = fl6_sock_lookup(sk, fl6.flowlabel);
8368c2ecf20Sopenharmony_ci			if (IS_ERR(flowlabel))
8378c2ecf20Sopenharmony_ci				return -EINVAL;
8388c2ecf20Sopenharmony_ci			fl6_sock_release(flowlabel);
8398c2ecf20Sopenharmony_ci		}
8408c2ecf20Sopenharmony_ci	}
8418c2ecf20Sopenharmony_ci	/*
8428c2ecf20Sopenharmony_ci	 * connect() to INADDR_ANY means loopback (BSD'ism).
8438c2ecf20Sopenharmony_ci	 */
8448c2ecf20Sopenharmony_ci	if (ipv6_addr_any(&usin->sin6_addr))
8458c2ecf20Sopenharmony_ci		usin->sin6_addr.s6_addr[15] = 1;
8468c2ecf20Sopenharmony_ci
8478c2ecf20Sopenharmony_ci	addr_type = ipv6_addr_type(&usin->sin6_addr);
8488c2ecf20Sopenharmony_ci
8498c2ecf20Sopenharmony_ci	if (addr_type & IPV6_ADDR_MULTICAST)
8508c2ecf20Sopenharmony_ci		return -ENETUNREACH;
8518c2ecf20Sopenharmony_ci
8528c2ecf20Sopenharmony_ci	if (addr_type & IPV6_ADDR_LINKLOCAL) {
8538c2ecf20Sopenharmony_ci		if (addr_len >= sizeof(struct sockaddr_in6) &&
8548c2ecf20Sopenharmony_ci		    usin->sin6_scope_id) {
8558c2ecf20Sopenharmony_ci			/* If interface is set while binding, indices
8568c2ecf20Sopenharmony_ci			 * must coincide.
8578c2ecf20Sopenharmony_ci			 */
8588c2ecf20Sopenharmony_ci			if (sk->sk_bound_dev_if &&
8598c2ecf20Sopenharmony_ci			    sk->sk_bound_dev_if != usin->sin6_scope_id)
8608c2ecf20Sopenharmony_ci				return -EINVAL;
8618c2ecf20Sopenharmony_ci
8628c2ecf20Sopenharmony_ci			sk->sk_bound_dev_if = usin->sin6_scope_id;
8638c2ecf20Sopenharmony_ci		}
8648c2ecf20Sopenharmony_ci
8658c2ecf20Sopenharmony_ci		/* Connect to link-local address requires an interface */
8668c2ecf20Sopenharmony_ci		if (!sk->sk_bound_dev_if)
8678c2ecf20Sopenharmony_ci			return -EINVAL;
8688c2ecf20Sopenharmony_ci	}
8698c2ecf20Sopenharmony_ci
8708c2ecf20Sopenharmony_ci	sk->sk_v6_daddr = usin->sin6_addr;
8718c2ecf20Sopenharmony_ci	np->flow_label = fl6.flowlabel;
8728c2ecf20Sopenharmony_ci
8738c2ecf20Sopenharmony_ci	/*
8748c2ecf20Sopenharmony_ci	 * DCCP over IPv4
8758c2ecf20Sopenharmony_ci	 */
8768c2ecf20Sopenharmony_ci	if (addr_type == IPV6_ADDR_MAPPED) {
8778c2ecf20Sopenharmony_ci		u32 exthdrlen = icsk->icsk_ext_hdr_len;
8788c2ecf20Sopenharmony_ci		struct sockaddr_in sin;
8798c2ecf20Sopenharmony_ci
8808c2ecf20Sopenharmony_ci		SOCK_DEBUG(sk, "connect: ipv4 mapped\n");
8818c2ecf20Sopenharmony_ci
8828c2ecf20Sopenharmony_ci		if (__ipv6_only_sock(sk))
8838c2ecf20Sopenharmony_ci			return -ENETUNREACH;
8848c2ecf20Sopenharmony_ci
8858c2ecf20Sopenharmony_ci		sin.sin_family = AF_INET;
8868c2ecf20Sopenharmony_ci		sin.sin_port = usin->sin6_port;
8878c2ecf20Sopenharmony_ci		sin.sin_addr.s_addr = usin->sin6_addr.s6_addr32[3];
8888c2ecf20Sopenharmony_ci
8898c2ecf20Sopenharmony_ci		icsk->icsk_af_ops = &dccp_ipv6_mapped;
8908c2ecf20Sopenharmony_ci		sk->sk_backlog_rcv = dccp_v4_do_rcv;
8918c2ecf20Sopenharmony_ci
8928c2ecf20Sopenharmony_ci		err = dccp_v4_connect(sk, (struct sockaddr *)&sin, sizeof(sin));
8938c2ecf20Sopenharmony_ci		if (err) {
8948c2ecf20Sopenharmony_ci			icsk->icsk_ext_hdr_len = exthdrlen;
8958c2ecf20Sopenharmony_ci			icsk->icsk_af_ops = &dccp_ipv6_af_ops;
8968c2ecf20Sopenharmony_ci			sk->sk_backlog_rcv = dccp_v6_do_rcv;
8978c2ecf20Sopenharmony_ci			goto failure;
8988c2ecf20Sopenharmony_ci		}
8998c2ecf20Sopenharmony_ci		np->saddr = sk->sk_v6_rcv_saddr;
9008c2ecf20Sopenharmony_ci		return err;
9018c2ecf20Sopenharmony_ci	}
9028c2ecf20Sopenharmony_ci
9038c2ecf20Sopenharmony_ci	if (!ipv6_addr_any(&sk->sk_v6_rcv_saddr))
9048c2ecf20Sopenharmony_ci		saddr = &sk->sk_v6_rcv_saddr;
9058c2ecf20Sopenharmony_ci
9068c2ecf20Sopenharmony_ci	fl6.flowi6_proto = IPPROTO_DCCP;
9078c2ecf20Sopenharmony_ci	fl6.daddr = sk->sk_v6_daddr;
9088c2ecf20Sopenharmony_ci	fl6.saddr = saddr ? *saddr : np->saddr;
9098c2ecf20Sopenharmony_ci	fl6.flowi6_oif = sk->sk_bound_dev_if;
9108c2ecf20Sopenharmony_ci	fl6.fl6_dport = usin->sin6_port;
9118c2ecf20Sopenharmony_ci	fl6.fl6_sport = inet->inet_sport;
9128c2ecf20Sopenharmony_ci	security_sk_classify_flow(sk, flowi6_to_flowi_common(&fl6));
9138c2ecf20Sopenharmony_ci
9148c2ecf20Sopenharmony_ci	opt = rcu_dereference_protected(np->opt, lockdep_sock_is_held(sk));
9158c2ecf20Sopenharmony_ci	final_p = fl6_update_dst(&fl6, opt, &final);
9168c2ecf20Sopenharmony_ci
9178c2ecf20Sopenharmony_ci	dst = ip6_dst_lookup_flow(sock_net(sk), sk, &fl6, final_p);
9188c2ecf20Sopenharmony_ci	if (IS_ERR(dst)) {
9198c2ecf20Sopenharmony_ci		err = PTR_ERR(dst);
9208c2ecf20Sopenharmony_ci		goto failure;
9218c2ecf20Sopenharmony_ci	}
9228c2ecf20Sopenharmony_ci
9238c2ecf20Sopenharmony_ci	if (saddr == NULL) {
9248c2ecf20Sopenharmony_ci		saddr = &fl6.saddr;
9258c2ecf20Sopenharmony_ci		sk->sk_v6_rcv_saddr = *saddr;
9268c2ecf20Sopenharmony_ci	}
9278c2ecf20Sopenharmony_ci
9288c2ecf20Sopenharmony_ci	/* set the source address */
9298c2ecf20Sopenharmony_ci	np->saddr = *saddr;
9308c2ecf20Sopenharmony_ci	inet->inet_rcv_saddr = LOOPBACK4_IPV6;
9318c2ecf20Sopenharmony_ci
9328c2ecf20Sopenharmony_ci	ip6_dst_store(sk, dst, NULL, NULL);
9338c2ecf20Sopenharmony_ci
9348c2ecf20Sopenharmony_ci	icsk->icsk_ext_hdr_len = 0;
9358c2ecf20Sopenharmony_ci	if (opt)
9368c2ecf20Sopenharmony_ci		icsk->icsk_ext_hdr_len = opt->opt_flen + opt->opt_nflen;
9378c2ecf20Sopenharmony_ci
9388c2ecf20Sopenharmony_ci	inet->inet_dport = usin->sin6_port;
9398c2ecf20Sopenharmony_ci
9408c2ecf20Sopenharmony_ci	dccp_set_state(sk, DCCP_REQUESTING);
9418c2ecf20Sopenharmony_ci	err = inet6_hash_connect(&dccp_death_row, sk);
9428c2ecf20Sopenharmony_ci	if (err)
9438c2ecf20Sopenharmony_ci		goto late_failure;
9448c2ecf20Sopenharmony_ci
9458c2ecf20Sopenharmony_ci	dp->dccps_iss = secure_dccpv6_sequence_number(np->saddr.s6_addr32,
9468c2ecf20Sopenharmony_ci						      sk->sk_v6_daddr.s6_addr32,
9478c2ecf20Sopenharmony_ci						      inet->inet_sport,
9488c2ecf20Sopenharmony_ci						      inet->inet_dport);
9498c2ecf20Sopenharmony_ci	err = dccp_connect(sk);
9508c2ecf20Sopenharmony_ci	if (err)
9518c2ecf20Sopenharmony_ci		goto late_failure;
9528c2ecf20Sopenharmony_ci
9538c2ecf20Sopenharmony_ci	return 0;
9548c2ecf20Sopenharmony_ci
9558c2ecf20Sopenharmony_cilate_failure:
9568c2ecf20Sopenharmony_ci	dccp_set_state(sk, DCCP_CLOSED);
9578c2ecf20Sopenharmony_ci	if (!(sk->sk_userlocks & SOCK_BINDADDR_LOCK))
9588c2ecf20Sopenharmony_ci		inet_reset_saddr(sk);
9598c2ecf20Sopenharmony_ci	__sk_dst_reset(sk);
9608c2ecf20Sopenharmony_cifailure:
9618c2ecf20Sopenharmony_ci	inet->inet_dport = 0;
9628c2ecf20Sopenharmony_ci	sk->sk_route_caps = 0;
9638c2ecf20Sopenharmony_ci	return err;
9648c2ecf20Sopenharmony_ci}
9658c2ecf20Sopenharmony_ci
9668c2ecf20Sopenharmony_cistatic const struct inet_connection_sock_af_ops dccp_ipv6_af_ops = {
9678c2ecf20Sopenharmony_ci	.queue_xmit	   = inet6_csk_xmit,
9688c2ecf20Sopenharmony_ci	.send_check	   = dccp_v6_send_check,
9698c2ecf20Sopenharmony_ci	.rebuild_header	   = inet6_sk_rebuild_header,
9708c2ecf20Sopenharmony_ci	.conn_request	   = dccp_v6_conn_request,
9718c2ecf20Sopenharmony_ci	.syn_recv_sock	   = dccp_v6_request_recv_sock,
9728c2ecf20Sopenharmony_ci	.net_header_len	   = sizeof(struct ipv6hdr),
9738c2ecf20Sopenharmony_ci	.setsockopt	   = ipv6_setsockopt,
9748c2ecf20Sopenharmony_ci	.getsockopt	   = ipv6_getsockopt,
9758c2ecf20Sopenharmony_ci	.addr2sockaddr	   = inet6_csk_addr2sockaddr,
9768c2ecf20Sopenharmony_ci	.sockaddr_len	   = sizeof(struct sockaddr_in6),
9778c2ecf20Sopenharmony_ci};
9788c2ecf20Sopenharmony_ci
9798c2ecf20Sopenharmony_ci/*
9808c2ecf20Sopenharmony_ci *	DCCP over IPv4 via INET6 API
9818c2ecf20Sopenharmony_ci */
9828c2ecf20Sopenharmony_cistatic const struct inet_connection_sock_af_ops dccp_ipv6_mapped = {
9838c2ecf20Sopenharmony_ci	.queue_xmit	   = ip_queue_xmit,
9848c2ecf20Sopenharmony_ci	.send_check	   = dccp_v4_send_check,
9858c2ecf20Sopenharmony_ci	.rebuild_header	   = inet_sk_rebuild_header,
9868c2ecf20Sopenharmony_ci	.conn_request	   = dccp_v6_conn_request,
9878c2ecf20Sopenharmony_ci	.syn_recv_sock	   = dccp_v6_request_recv_sock,
9888c2ecf20Sopenharmony_ci	.net_header_len	   = sizeof(struct iphdr),
9898c2ecf20Sopenharmony_ci	.setsockopt	   = ipv6_setsockopt,
9908c2ecf20Sopenharmony_ci	.getsockopt	   = ipv6_getsockopt,
9918c2ecf20Sopenharmony_ci	.addr2sockaddr	   = inet6_csk_addr2sockaddr,
9928c2ecf20Sopenharmony_ci	.sockaddr_len	   = sizeof(struct sockaddr_in6),
9938c2ecf20Sopenharmony_ci};
9948c2ecf20Sopenharmony_ci
9958c2ecf20Sopenharmony_cistatic void dccp_v6_sk_destruct(struct sock *sk)
9968c2ecf20Sopenharmony_ci{
9978c2ecf20Sopenharmony_ci	dccp_destruct_common(sk);
9988c2ecf20Sopenharmony_ci	inet6_sock_destruct(sk);
9998c2ecf20Sopenharmony_ci}
10008c2ecf20Sopenharmony_ci
10018c2ecf20Sopenharmony_ci/* NOTE: A lot of things set to zero explicitly by call to
10028c2ecf20Sopenharmony_ci *       sk_alloc() so need not be done here.
10038c2ecf20Sopenharmony_ci */
10048c2ecf20Sopenharmony_cistatic int dccp_v6_init_sock(struct sock *sk)
10058c2ecf20Sopenharmony_ci{
10068c2ecf20Sopenharmony_ci	static __u8 dccp_v6_ctl_sock_initialized;
10078c2ecf20Sopenharmony_ci	int err = dccp_init_sock(sk, dccp_v6_ctl_sock_initialized);
10088c2ecf20Sopenharmony_ci
10098c2ecf20Sopenharmony_ci	if (err == 0) {
10108c2ecf20Sopenharmony_ci		if (unlikely(!dccp_v6_ctl_sock_initialized))
10118c2ecf20Sopenharmony_ci			dccp_v6_ctl_sock_initialized = 1;
10128c2ecf20Sopenharmony_ci		inet_csk(sk)->icsk_af_ops = &dccp_ipv6_af_ops;
10138c2ecf20Sopenharmony_ci		sk->sk_destruct = dccp_v6_sk_destruct;
10148c2ecf20Sopenharmony_ci	}
10158c2ecf20Sopenharmony_ci
10168c2ecf20Sopenharmony_ci	return err;
10178c2ecf20Sopenharmony_ci}
10188c2ecf20Sopenharmony_ci
10198c2ecf20Sopenharmony_cistatic struct timewait_sock_ops dccp6_timewait_sock_ops = {
10208c2ecf20Sopenharmony_ci	.twsk_obj_size	= sizeof(struct dccp6_timewait_sock),
10218c2ecf20Sopenharmony_ci};
10228c2ecf20Sopenharmony_ci
10238c2ecf20Sopenharmony_cistatic struct proto dccp_v6_prot = {
10248c2ecf20Sopenharmony_ci	.name		   = "DCCPv6",
10258c2ecf20Sopenharmony_ci	.owner		   = THIS_MODULE,
10268c2ecf20Sopenharmony_ci	.close		   = dccp_close,
10278c2ecf20Sopenharmony_ci	.connect	   = dccp_v6_connect,
10288c2ecf20Sopenharmony_ci	.disconnect	   = dccp_disconnect,
10298c2ecf20Sopenharmony_ci	.ioctl		   = dccp_ioctl,
10308c2ecf20Sopenharmony_ci	.init		   = dccp_v6_init_sock,
10318c2ecf20Sopenharmony_ci	.setsockopt	   = dccp_setsockopt,
10328c2ecf20Sopenharmony_ci	.getsockopt	   = dccp_getsockopt,
10338c2ecf20Sopenharmony_ci	.sendmsg	   = dccp_sendmsg,
10348c2ecf20Sopenharmony_ci	.recvmsg	   = dccp_recvmsg,
10358c2ecf20Sopenharmony_ci	.backlog_rcv	   = dccp_v6_do_rcv,
10368c2ecf20Sopenharmony_ci	.hash		   = inet6_hash,
10378c2ecf20Sopenharmony_ci	.unhash		   = inet_unhash,
10388c2ecf20Sopenharmony_ci	.accept		   = inet_csk_accept,
10398c2ecf20Sopenharmony_ci	.get_port	   = inet_csk_get_port,
10408c2ecf20Sopenharmony_ci	.shutdown	   = dccp_shutdown,
10418c2ecf20Sopenharmony_ci	.destroy	   = dccp_destroy_sock,
10428c2ecf20Sopenharmony_ci	.orphan_count	   = &dccp_orphan_count,
10438c2ecf20Sopenharmony_ci	.max_header	   = MAX_DCCP_HEADER,
10448c2ecf20Sopenharmony_ci	.obj_size	   = sizeof(struct dccp6_sock),
10458c2ecf20Sopenharmony_ci	.slab_flags	   = SLAB_TYPESAFE_BY_RCU,
10468c2ecf20Sopenharmony_ci	.rsk_prot	   = &dccp6_request_sock_ops,
10478c2ecf20Sopenharmony_ci	.twsk_prot	   = &dccp6_timewait_sock_ops,
10488c2ecf20Sopenharmony_ci	.h.hashinfo	   = &dccp_hashinfo,
10498c2ecf20Sopenharmony_ci};
10508c2ecf20Sopenharmony_ci
10518c2ecf20Sopenharmony_cistatic const struct inet6_protocol dccp_v6_protocol = {
10528c2ecf20Sopenharmony_ci	.handler	= dccp_v6_rcv,
10538c2ecf20Sopenharmony_ci	.err_handler	= dccp_v6_err,
10548c2ecf20Sopenharmony_ci	.flags		= INET6_PROTO_NOPOLICY | INET6_PROTO_FINAL,
10558c2ecf20Sopenharmony_ci};
10568c2ecf20Sopenharmony_ci
10578c2ecf20Sopenharmony_cistatic const struct proto_ops inet6_dccp_ops = {
10588c2ecf20Sopenharmony_ci	.family		   = PF_INET6,
10598c2ecf20Sopenharmony_ci	.owner		   = THIS_MODULE,
10608c2ecf20Sopenharmony_ci	.release	   = inet6_release,
10618c2ecf20Sopenharmony_ci	.bind		   = inet6_bind,
10628c2ecf20Sopenharmony_ci	.connect	   = inet_stream_connect,
10638c2ecf20Sopenharmony_ci	.socketpair	   = sock_no_socketpair,
10648c2ecf20Sopenharmony_ci	.accept		   = inet_accept,
10658c2ecf20Sopenharmony_ci	.getname	   = inet6_getname,
10668c2ecf20Sopenharmony_ci	.poll		   = dccp_poll,
10678c2ecf20Sopenharmony_ci	.ioctl		   = inet6_ioctl,
10688c2ecf20Sopenharmony_ci	.gettstamp	   = sock_gettstamp,
10698c2ecf20Sopenharmony_ci	.listen		   = inet_dccp_listen,
10708c2ecf20Sopenharmony_ci	.shutdown	   = inet_shutdown,
10718c2ecf20Sopenharmony_ci	.setsockopt	   = sock_common_setsockopt,
10728c2ecf20Sopenharmony_ci	.getsockopt	   = sock_common_getsockopt,
10738c2ecf20Sopenharmony_ci	.sendmsg	   = inet_sendmsg,
10748c2ecf20Sopenharmony_ci	.recvmsg	   = sock_common_recvmsg,
10758c2ecf20Sopenharmony_ci	.mmap		   = sock_no_mmap,
10768c2ecf20Sopenharmony_ci	.sendpage	   = sock_no_sendpage,
10778c2ecf20Sopenharmony_ci#ifdef CONFIG_COMPAT
10788c2ecf20Sopenharmony_ci	.compat_ioctl	   = inet6_compat_ioctl,
10798c2ecf20Sopenharmony_ci#endif
10808c2ecf20Sopenharmony_ci};
10818c2ecf20Sopenharmony_ci
10828c2ecf20Sopenharmony_cistatic struct inet_protosw dccp_v6_protosw = {
10838c2ecf20Sopenharmony_ci	.type		= SOCK_DCCP,
10848c2ecf20Sopenharmony_ci	.protocol	= IPPROTO_DCCP,
10858c2ecf20Sopenharmony_ci	.prot		= &dccp_v6_prot,
10868c2ecf20Sopenharmony_ci	.ops		= &inet6_dccp_ops,
10878c2ecf20Sopenharmony_ci	.flags		= INET_PROTOSW_ICSK,
10888c2ecf20Sopenharmony_ci};
10898c2ecf20Sopenharmony_ci
10908c2ecf20Sopenharmony_cistatic int __net_init dccp_v6_init_net(struct net *net)
10918c2ecf20Sopenharmony_ci{
10928c2ecf20Sopenharmony_ci	if (dccp_hashinfo.bhash == NULL)
10938c2ecf20Sopenharmony_ci		return -ESOCKTNOSUPPORT;
10948c2ecf20Sopenharmony_ci
10958c2ecf20Sopenharmony_ci	return inet_ctl_sock_create(&net->dccp.v6_ctl_sk, PF_INET6,
10968c2ecf20Sopenharmony_ci				    SOCK_DCCP, IPPROTO_DCCP, net);
10978c2ecf20Sopenharmony_ci}
10988c2ecf20Sopenharmony_ci
10998c2ecf20Sopenharmony_cistatic void __net_exit dccp_v6_exit_net(struct net *net)
11008c2ecf20Sopenharmony_ci{
11018c2ecf20Sopenharmony_ci	inet_ctl_sock_destroy(net->dccp.v6_ctl_sk);
11028c2ecf20Sopenharmony_ci}
11038c2ecf20Sopenharmony_ci
11048c2ecf20Sopenharmony_cistatic void __net_exit dccp_v6_exit_batch(struct list_head *net_exit_list)
11058c2ecf20Sopenharmony_ci{
11068c2ecf20Sopenharmony_ci	inet_twsk_purge(&dccp_hashinfo, AF_INET6);
11078c2ecf20Sopenharmony_ci}
11088c2ecf20Sopenharmony_ci
11098c2ecf20Sopenharmony_cistatic struct pernet_operations dccp_v6_ops = {
11108c2ecf20Sopenharmony_ci	.init   = dccp_v6_init_net,
11118c2ecf20Sopenharmony_ci	.exit   = dccp_v6_exit_net,
11128c2ecf20Sopenharmony_ci	.exit_batch = dccp_v6_exit_batch,
11138c2ecf20Sopenharmony_ci};
11148c2ecf20Sopenharmony_ci
11158c2ecf20Sopenharmony_cistatic int __init dccp_v6_init(void)
11168c2ecf20Sopenharmony_ci{
11178c2ecf20Sopenharmony_ci	int err = proto_register(&dccp_v6_prot, 1);
11188c2ecf20Sopenharmony_ci
11198c2ecf20Sopenharmony_ci	if (err)
11208c2ecf20Sopenharmony_ci		goto out;
11218c2ecf20Sopenharmony_ci
11228c2ecf20Sopenharmony_ci	inet6_register_protosw(&dccp_v6_protosw);
11238c2ecf20Sopenharmony_ci
11248c2ecf20Sopenharmony_ci	err = register_pernet_subsys(&dccp_v6_ops);
11258c2ecf20Sopenharmony_ci	if (err)
11268c2ecf20Sopenharmony_ci		goto out_destroy_ctl_sock;
11278c2ecf20Sopenharmony_ci
11288c2ecf20Sopenharmony_ci	err = inet6_add_protocol(&dccp_v6_protocol, IPPROTO_DCCP);
11298c2ecf20Sopenharmony_ci	if (err)
11308c2ecf20Sopenharmony_ci		goto out_unregister_proto;
11318c2ecf20Sopenharmony_ci
11328c2ecf20Sopenharmony_ciout:
11338c2ecf20Sopenharmony_ci	return err;
11348c2ecf20Sopenharmony_ciout_unregister_proto:
11358c2ecf20Sopenharmony_ci	unregister_pernet_subsys(&dccp_v6_ops);
11368c2ecf20Sopenharmony_ciout_destroy_ctl_sock:
11378c2ecf20Sopenharmony_ci	inet6_unregister_protosw(&dccp_v6_protosw);
11388c2ecf20Sopenharmony_ci	proto_unregister(&dccp_v6_prot);
11398c2ecf20Sopenharmony_ci	goto out;
11408c2ecf20Sopenharmony_ci}
11418c2ecf20Sopenharmony_ci
11428c2ecf20Sopenharmony_cistatic void __exit dccp_v6_exit(void)
11438c2ecf20Sopenharmony_ci{
11448c2ecf20Sopenharmony_ci	inet6_del_protocol(&dccp_v6_protocol, IPPROTO_DCCP);
11458c2ecf20Sopenharmony_ci	unregister_pernet_subsys(&dccp_v6_ops);
11468c2ecf20Sopenharmony_ci	inet6_unregister_protosw(&dccp_v6_protosw);
11478c2ecf20Sopenharmony_ci	proto_unregister(&dccp_v6_prot);
11488c2ecf20Sopenharmony_ci}
11498c2ecf20Sopenharmony_ci
11508c2ecf20Sopenharmony_cimodule_init(dccp_v6_init);
11518c2ecf20Sopenharmony_cimodule_exit(dccp_v6_exit);
11528c2ecf20Sopenharmony_ci
11538c2ecf20Sopenharmony_ci/*
11548c2ecf20Sopenharmony_ci * __stringify doesn't likes enums, so use SOCK_DCCP (6) and IPPROTO_DCCP (33)
11558c2ecf20Sopenharmony_ci * values directly, Also cover the case where the protocol is not specified,
11568c2ecf20Sopenharmony_ci * i.e. net-pf-PF_INET6-proto-0-type-SOCK_DCCP
11578c2ecf20Sopenharmony_ci */
11588c2ecf20Sopenharmony_ciMODULE_ALIAS_NET_PF_PROTO_TYPE(PF_INET6, 33, 6);
11598c2ecf20Sopenharmony_ciMODULE_ALIAS_NET_PF_PROTO_TYPE(PF_INET6, 0, 6);
11608c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
11618c2ecf20Sopenharmony_ciMODULE_AUTHOR("Arnaldo Carvalho de Melo <acme@mandriva.com>");
11628c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("DCCPv6 - Datagram Congestion Controlled Protocol");
1163