xref: /kernel/linux/linux-5.10/net/ipv6/ip6_output.c (revision 8c2ecf20)
18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci *	IPv6 output functions
48c2ecf20Sopenharmony_ci *	Linux INET6 implementation
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci *	Authors:
78c2ecf20Sopenharmony_ci *	Pedro Roque		<roque@di.fc.ul.pt>
88c2ecf20Sopenharmony_ci *
98c2ecf20Sopenharmony_ci *	Based on linux/net/ipv4/ip_output.c
108c2ecf20Sopenharmony_ci *
118c2ecf20Sopenharmony_ci *	Changes:
128c2ecf20Sopenharmony_ci *	A.N.Kuznetsov	:	airthmetics in fragmentation.
138c2ecf20Sopenharmony_ci *				extension headers are implemented.
148c2ecf20Sopenharmony_ci *				route changes now work.
158c2ecf20Sopenharmony_ci *				ip6_forward does not confuse sniffers.
168c2ecf20Sopenharmony_ci *				etc.
178c2ecf20Sopenharmony_ci *
188c2ecf20Sopenharmony_ci *      H. von Brand    :       Added missing #include <linux/string.h>
198c2ecf20Sopenharmony_ci *	Imran Patel	:	frag id should be in NBO
208c2ecf20Sopenharmony_ci *      Kazunori MIYAZAWA @USAGI
218c2ecf20Sopenharmony_ci *			:       add ip6_append_data and related functions
228c2ecf20Sopenharmony_ci *				for datagram xmit
238c2ecf20Sopenharmony_ci */
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci#include <linux/errno.h>
268c2ecf20Sopenharmony_ci#include <linux/kernel.h>
278c2ecf20Sopenharmony_ci#include <linux/string.h>
288c2ecf20Sopenharmony_ci#include <linux/socket.h>
298c2ecf20Sopenharmony_ci#include <linux/net.h>
308c2ecf20Sopenharmony_ci#include <linux/netdevice.h>
318c2ecf20Sopenharmony_ci#include <linux/if_arp.h>
328c2ecf20Sopenharmony_ci#include <linux/in6.h>
338c2ecf20Sopenharmony_ci#include <linux/tcp.h>
348c2ecf20Sopenharmony_ci#include <linux/route.h>
358c2ecf20Sopenharmony_ci#include <linux/module.h>
368c2ecf20Sopenharmony_ci#include <linux/slab.h>
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_ci#include <linux/bpf-cgroup.h>
398c2ecf20Sopenharmony_ci#include <linux/netfilter.h>
408c2ecf20Sopenharmony_ci#include <linux/netfilter_ipv6.h>
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci#include <net/sock.h>
438c2ecf20Sopenharmony_ci#include <net/snmp.h>
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_ci#include <net/ipv6.h>
468c2ecf20Sopenharmony_ci#include <net/ndisc.h>
478c2ecf20Sopenharmony_ci#include <net/protocol.h>
488c2ecf20Sopenharmony_ci#include <net/ip6_route.h>
498c2ecf20Sopenharmony_ci#include <net/addrconf.h>
508c2ecf20Sopenharmony_ci#include <net/rawv6.h>
518c2ecf20Sopenharmony_ci#include <net/icmp.h>
528c2ecf20Sopenharmony_ci#include <net/xfrm.h>
538c2ecf20Sopenharmony_ci#include <net/checksum.h>
548c2ecf20Sopenharmony_ci#include <linux/mroute6.h>
558c2ecf20Sopenharmony_ci#include <net/l3mdev.h>
568c2ecf20Sopenharmony_ci#include <net/lwtunnel.h>
578c2ecf20Sopenharmony_ci#include <net/ip_tunnels.h>
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_cistatic int ip6_finish_output2(struct net *net, struct sock *sk, struct sk_buff *skb)
608c2ecf20Sopenharmony_ci{
618c2ecf20Sopenharmony_ci	struct dst_entry *dst = skb_dst(skb);
628c2ecf20Sopenharmony_ci	struct net_device *dev = dst->dev;
638c2ecf20Sopenharmony_ci	unsigned int hh_len = LL_RESERVED_SPACE(dev);
648c2ecf20Sopenharmony_ci	int delta = hh_len - skb_headroom(skb);
658c2ecf20Sopenharmony_ci	const struct in6_addr *nexthop;
668c2ecf20Sopenharmony_ci	struct neighbour *neigh;
678c2ecf20Sopenharmony_ci	int ret;
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ci	/* Be paranoid, rather than too clever. */
708c2ecf20Sopenharmony_ci	if (unlikely(delta > 0) && dev->header_ops) {
718c2ecf20Sopenharmony_ci		/* pskb_expand_head() might crash, if skb is shared */
728c2ecf20Sopenharmony_ci		if (skb_shared(skb)) {
738c2ecf20Sopenharmony_ci			struct sk_buff *nskb = skb_clone(skb, GFP_ATOMIC);
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ci			if (likely(nskb)) {
768c2ecf20Sopenharmony_ci				if (skb->sk)
778c2ecf20Sopenharmony_ci					skb_set_owner_w(nskb, skb->sk);
788c2ecf20Sopenharmony_ci				consume_skb(skb);
798c2ecf20Sopenharmony_ci			} else {
808c2ecf20Sopenharmony_ci				kfree_skb(skb);
818c2ecf20Sopenharmony_ci			}
828c2ecf20Sopenharmony_ci			skb = nskb;
838c2ecf20Sopenharmony_ci		}
848c2ecf20Sopenharmony_ci		if (skb &&
858c2ecf20Sopenharmony_ci		    pskb_expand_head(skb, SKB_DATA_ALIGN(delta), 0, GFP_ATOMIC)) {
868c2ecf20Sopenharmony_ci			kfree_skb(skb);
878c2ecf20Sopenharmony_ci			skb = NULL;
888c2ecf20Sopenharmony_ci		}
898c2ecf20Sopenharmony_ci		if (!skb) {
908c2ecf20Sopenharmony_ci			IP6_INC_STATS(net, ip6_dst_idev(dst), IPSTATS_MIB_OUTDISCARDS);
918c2ecf20Sopenharmony_ci			return -ENOMEM;
928c2ecf20Sopenharmony_ci		}
938c2ecf20Sopenharmony_ci	}
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_ci	if (ipv6_addr_is_multicast(&ipv6_hdr(skb)->daddr)) {
968c2ecf20Sopenharmony_ci		struct inet6_dev *idev = ip6_dst_idev(skb_dst(skb));
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci		if (!(dev->flags & IFF_LOOPBACK) && sk_mc_loop(sk) &&
998c2ecf20Sopenharmony_ci		    ((mroute6_is_socket(net, skb) &&
1008c2ecf20Sopenharmony_ci		     !(IP6CB(skb)->flags & IP6SKB_FORWARDED)) ||
1018c2ecf20Sopenharmony_ci		     ipv6_chk_mcast_addr(dev, &ipv6_hdr(skb)->daddr,
1028c2ecf20Sopenharmony_ci					 &ipv6_hdr(skb)->saddr))) {
1038c2ecf20Sopenharmony_ci			struct sk_buff *newskb = skb_clone(skb, GFP_ATOMIC);
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci			/* Do not check for IFF_ALLMULTI; multicast routing
1068c2ecf20Sopenharmony_ci			   is not supported in any case.
1078c2ecf20Sopenharmony_ci			 */
1088c2ecf20Sopenharmony_ci			if (newskb)
1098c2ecf20Sopenharmony_ci				NF_HOOK(NFPROTO_IPV6, NF_INET_POST_ROUTING,
1108c2ecf20Sopenharmony_ci					net, sk, newskb, NULL, newskb->dev,
1118c2ecf20Sopenharmony_ci					dev_loopback_xmit);
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci			if (ipv6_hdr(skb)->hop_limit == 0) {
1148c2ecf20Sopenharmony_ci				IP6_INC_STATS(net, idev,
1158c2ecf20Sopenharmony_ci					      IPSTATS_MIB_OUTDISCARDS);
1168c2ecf20Sopenharmony_ci				kfree_skb(skb);
1178c2ecf20Sopenharmony_ci				return 0;
1188c2ecf20Sopenharmony_ci			}
1198c2ecf20Sopenharmony_ci		}
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ci		IP6_UPD_PO_STATS(net, idev, IPSTATS_MIB_OUTMCAST, skb->len);
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_ci		if (IPV6_ADDR_MC_SCOPE(&ipv6_hdr(skb)->daddr) <=
1248c2ecf20Sopenharmony_ci		    IPV6_ADDR_SCOPE_NODELOCAL &&
1258c2ecf20Sopenharmony_ci		    !(dev->flags & IFF_LOOPBACK)) {
1268c2ecf20Sopenharmony_ci			kfree_skb(skb);
1278c2ecf20Sopenharmony_ci			return 0;
1288c2ecf20Sopenharmony_ci		}
1298c2ecf20Sopenharmony_ci	}
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_ci	if (lwtunnel_xmit_redirect(dst->lwtstate)) {
1328c2ecf20Sopenharmony_ci		int res = lwtunnel_xmit(skb);
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_ci		if (res != LWTUNNEL_XMIT_CONTINUE)
1358c2ecf20Sopenharmony_ci			return res;
1368c2ecf20Sopenharmony_ci	}
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_ci	rcu_read_lock_bh();
1398c2ecf20Sopenharmony_ci	nexthop = rt6_nexthop((struct rt6_info *)dst, &ipv6_hdr(skb)->daddr);
1408c2ecf20Sopenharmony_ci	neigh = __ipv6_neigh_lookup_noref(dst->dev, nexthop);
1418c2ecf20Sopenharmony_ci	if (unlikely(!neigh))
1428c2ecf20Sopenharmony_ci		neigh = __neigh_create(&nd_tbl, nexthop, dst->dev, false);
1438c2ecf20Sopenharmony_ci	if (!IS_ERR(neigh)) {
1448c2ecf20Sopenharmony_ci		sock_confirm_neigh(skb, neigh);
1458c2ecf20Sopenharmony_ci		ret = neigh_output(neigh, skb, false);
1468c2ecf20Sopenharmony_ci		rcu_read_unlock_bh();
1478c2ecf20Sopenharmony_ci		return ret;
1488c2ecf20Sopenharmony_ci	}
1498c2ecf20Sopenharmony_ci	rcu_read_unlock_bh();
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_ci	IP6_INC_STATS(net, ip6_dst_idev(dst), IPSTATS_MIB_OUTNOROUTES);
1528c2ecf20Sopenharmony_ci	kfree_skb(skb);
1538c2ecf20Sopenharmony_ci	return -EINVAL;
1548c2ecf20Sopenharmony_ci}
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_cistatic int
1578c2ecf20Sopenharmony_ciip6_finish_output_gso_slowpath_drop(struct net *net, struct sock *sk,
1588c2ecf20Sopenharmony_ci				    struct sk_buff *skb, unsigned int mtu)
1598c2ecf20Sopenharmony_ci{
1608c2ecf20Sopenharmony_ci	struct sk_buff *segs, *nskb;
1618c2ecf20Sopenharmony_ci	netdev_features_t features;
1628c2ecf20Sopenharmony_ci	int ret = 0;
1638c2ecf20Sopenharmony_ci
1648c2ecf20Sopenharmony_ci	/* Please see corresponding comment in ip_finish_output_gso
1658c2ecf20Sopenharmony_ci	 * describing the cases where GSO segment length exceeds the
1668c2ecf20Sopenharmony_ci	 * egress MTU.
1678c2ecf20Sopenharmony_ci	 */
1688c2ecf20Sopenharmony_ci	features = netif_skb_features(skb);
1698c2ecf20Sopenharmony_ci	segs = skb_gso_segment(skb, features & ~NETIF_F_GSO_MASK);
1708c2ecf20Sopenharmony_ci	if (IS_ERR_OR_NULL(segs)) {
1718c2ecf20Sopenharmony_ci		kfree_skb(skb);
1728c2ecf20Sopenharmony_ci		return -ENOMEM;
1738c2ecf20Sopenharmony_ci	}
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_ci	consume_skb(skb);
1768c2ecf20Sopenharmony_ci
1778c2ecf20Sopenharmony_ci	skb_list_walk_safe(segs, segs, nskb) {
1788c2ecf20Sopenharmony_ci		int err;
1798c2ecf20Sopenharmony_ci
1808c2ecf20Sopenharmony_ci		skb_mark_not_on_list(segs);
1818c2ecf20Sopenharmony_ci		/* Last GSO segment can be smaller than gso_size (and MTU).
1828c2ecf20Sopenharmony_ci		 * Adding a fragment header would produce an "atomic fragment",
1838c2ecf20Sopenharmony_ci		 * which is considered harmful (RFC-8021). Avoid that.
1848c2ecf20Sopenharmony_ci		 */
1858c2ecf20Sopenharmony_ci		err = segs->len > mtu ?
1868c2ecf20Sopenharmony_ci			ip6_fragment(net, sk, segs, ip6_finish_output2) :
1878c2ecf20Sopenharmony_ci			ip6_finish_output2(net, sk, segs);
1888c2ecf20Sopenharmony_ci		if (err && ret == 0)
1898c2ecf20Sopenharmony_ci			ret = err;
1908c2ecf20Sopenharmony_ci	}
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_ci	return ret;
1938c2ecf20Sopenharmony_ci}
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_cistatic int __ip6_finish_output(struct net *net, struct sock *sk, struct sk_buff *skb)
1968c2ecf20Sopenharmony_ci{
1978c2ecf20Sopenharmony_ci	unsigned int mtu;
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_ci#if defined(CONFIG_NETFILTER) && defined(CONFIG_XFRM)
2008c2ecf20Sopenharmony_ci	/* Policy lookup after SNAT yielded a new policy */
2018c2ecf20Sopenharmony_ci	if (skb_dst(skb)->xfrm) {
2028c2ecf20Sopenharmony_ci		IP6CB(skb)->flags |= IP6SKB_REROUTED;
2038c2ecf20Sopenharmony_ci		return dst_output(net, sk, skb);
2048c2ecf20Sopenharmony_ci	}
2058c2ecf20Sopenharmony_ci#endif
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_ci	mtu = ip6_skb_dst_mtu(skb);
2088c2ecf20Sopenharmony_ci	if (skb_is_gso(skb) && !skb_gso_validate_network_len(skb, mtu))
2098c2ecf20Sopenharmony_ci		return ip6_finish_output_gso_slowpath_drop(net, sk, skb, mtu);
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_ci	if ((skb->len > mtu && !skb_is_gso(skb)) ||
2128c2ecf20Sopenharmony_ci	    dst_allfrag(skb_dst(skb)) ||
2138c2ecf20Sopenharmony_ci	    (IP6CB(skb)->frag_max_size && skb->len > IP6CB(skb)->frag_max_size))
2148c2ecf20Sopenharmony_ci		return ip6_fragment(net, sk, skb, ip6_finish_output2);
2158c2ecf20Sopenharmony_ci	else
2168c2ecf20Sopenharmony_ci		return ip6_finish_output2(net, sk, skb);
2178c2ecf20Sopenharmony_ci}
2188c2ecf20Sopenharmony_ci
2198c2ecf20Sopenharmony_cistatic int ip6_finish_output(struct net *net, struct sock *sk, struct sk_buff *skb)
2208c2ecf20Sopenharmony_ci{
2218c2ecf20Sopenharmony_ci	int ret;
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_ci	ret = BPF_CGROUP_RUN_PROG_INET_EGRESS(sk, skb);
2248c2ecf20Sopenharmony_ci	switch (ret) {
2258c2ecf20Sopenharmony_ci	case NET_XMIT_SUCCESS:
2268c2ecf20Sopenharmony_ci		return __ip6_finish_output(net, sk, skb);
2278c2ecf20Sopenharmony_ci	case NET_XMIT_CN:
2288c2ecf20Sopenharmony_ci		return __ip6_finish_output(net, sk, skb) ? : ret;
2298c2ecf20Sopenharmony_ci	default:
2308c2ecf20Sopenharmony_ci		kfree_skb(skb);
2318c2ecf20Sopenharmony_ci		return ret;
2328c2ecf20Sopenharmony_ci	}
2338c2ecf20Sopenharmony_ci}
2348c2ecf20Sopenharmony_ci
2358c2ecf20Sopenharmony_ciint ip6_output(struct net *net, struct sock *sk, struct sk_buff *skb)
2368c2ecf20Sopenharmony_ci{
2378c2ecf20Sopenharmony_ci	struct net_device *dev = skb_dst(skb)->dev, *indev = skb->dev;
2388c2ecf20Sopenharmony_ci	struct inet6_dev *idev = ip6_dst_idev(skb_dst(skb));
2398c2ecf20Sopenharmony_ci
2408c2ecf20Sopenharmony_ci	skb->protocol = htons(ETH_P_IPV6);
2418c2ecf20Sopenharmony_ci	skb->dev = dev;
2428c2ecf20Sopenharmony_ci
2438c2ecf20Sopenharmony_ci	if (unlikely(!idev || (idev->cnf.disable_ipv6))) {
2448c2ecf20Sopenharmony_ci		IP6_INC_STATS(net, idev, IPSTATS_MIB_OUTDISCARDS);
2458c2ecf20Sopenharmony_ci		kfree_skb(skb);
2468c2ecf20Sopenharmony_ci		return 0;
2478c2ecf20Sopenharmony_ci	}
2488c2ecf20Sopenharmony_ci
2498c2ecf20Sopenharmony_ci	return NF_HOOK_COND(NFPROTO_IPV6, NF_INET_POST_ROUTING,
2508c2ecf20Sopenharmony_ci			    net, sk, skb, indev, dev,
2518c2ecf20Sopenharmony_ci			    ip6_finish_output,
2528c2ecf20Sopenharmony_ci			    !(IP6CB(skb)->flags & IP6SKB_REROUTED));
2538c2ecf20Sopenharmony_ci}
2548c2ecf20Sopenharmony_ci
2558c2ecf20Sopenharmony_cibool ip6_autoflowlabel(struct net *net, const struct ipv6_pinfo *np)
2568c2ecf20Sopenharmony_ci{
2578c2ecf20Sopenharmony_ci	if (!np->autoflowlabel_set)
2588c2ecf20Sopenharmony_ci		return ip6_default_np_autolabel(net);
2598c2ecf20Sopenharmony_ci	else
2608c2ecf20Sopenharmony_ci		return np->autoflowlabel;
2618c2ecf20Sopenharmony_ci}
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_ci/*
2648c2ecf20Sopenharmony_ci * xmit an sk_buff (used by TCP, SCTP and DCCP)
2658c2ecf20Sopenharmony_ci * Note : socket lock is not held for SYNACK packets, but might be modified
2668c2ecf20Sopenharmony_ci * by calls to skb_set_owner_w() and ipv6_local_error(),
2678c2ecf20Sopenharmony_ci * which are using proper atomic operations or spinlocks.
2688c2ecf20Sopenharmony_ci */
2698c2ecf20Sopenharmony_ciint ip6_xmit(const struct sock *sk, struct sk_buff *skb, struct flowi6 *fl6,
2708c2ecf20Sopenharmony_ci	     __u32 mark, struct ipv6_txoptions *opt, int tclass, u32 priority)
2718c2ecf20Sopenharmony_ci{
2728c2ecf20Sopenharmony_ci	struct net *net = sock_net(sk);
2738c2ecf20Sopenharmony_ci	const struct ipv6_pinfo *np = inet6_sk(sk);
2748c2ecf20Sopenharmony_ci	struct in6_addr *first_hop = &fl6->daddr;
2758c2ecf20Sopenharmony_ci	struct dst_entry *dst = skb_dst(skb);
2768c2ecf20Sopenharmony_ci	unsigned int head_room;
2778c2ecf20Sopenharmony_ci	struct ipv6hdr *hdr;
2788c2ecf20Sopenharmony_ci	u8  proto = fl6->flowi6_proto;
2798c2ecf20Sopenharmony_ci	int seg_len = skb->len;
2808c2ecf20Sopenharmony_ci	int hlimit = -1;
2818c2ecf20Sopenharmony_ci	u32 mtu;
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_ci	head_room = sizeof(struct ipv6hdr) + LL_RESERVED_SPACE(dst->dev);
2848c2ecf20Sopenharmony_ci	if (opt)
2858c2ecf20Sopenharmony_ci		head_room += opt->opt_nflen + opt->opt_flen;
2868c2ecf20Sopenharmony_ci
2878c2ecf20Sopenharmony_ci	if (unlikely(skb_headroom(skb) < head_room)) {
2888c2ecf20Sopenharmony_ci		struct sk_buff *skb2 = skb_realloc_headroom(skb, head_room);
2898c2ecf20Sopenharmony_ci		if (!skb2) {
2908c2ecf20Sopenharmony_ci			IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)),
2918c2ecf20Sopenharmony_ci				      IPSTATS_MIB_OUTDISCARDS);
2928c2ecf20Sopenharmony_ci			kfree_skb(skb);
2938c2ecf20Sopenharmony_ci			return -ENOBUFS;
2948c2ecf20Sopenharmony_ci		}
2958c2ecf20Sopenharmony_ci		if (skb->sk)
2968c2ecf20Sopenharmony_ci			skb_set_owner_w(skb2, skb->sk);
2978c2ecf20Sopenharmony_ci		consume_skb(skb);
2988c2ecf20Sopenharmony_ci		skb = skb2;
2998c2ecf20Sopenharmony_ci	}
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_ci	if (opt) {
3028c2ecf20Sopenharmony_ci		seg_len += opt->opt_nflen + opt->opt_flen;
3038c2ecf20Sopenharmony_ci
3048c2ecf20Sopenharmony_ci		if (opt->opt_flen)
3058c2ecf20Sopenharmony_ci			ipv6_push_frag_opts(skb, opt, &proto);
3068c2ecf20Sopenharmony_ci
3078c2ecf20Sopenharmony_ci		if (opt->opt_nflen)
3088c2ecf20Sopenharmony_ci			ipv6_push_nfrag_opts(skb, opt, &proto, &first_hop,
3098c2ecf20Sopenharmony_ci					     &fl6->saddr);
3108c2ecf20Sopenharmony_ci	}
3118c2ecf20Sopenharmony_ci
3128c2ecf20Sopenharmony_ci	skb_push(skb, sizeof(struct ipv6hdr));
3138c2ecf20Sopenharmony_ci	skb_reset_network_header(skb);
3148c2ecf20Sopenharmony_ci	hdr = ipv6_hdr(skb);
3158c2ecf20Sopenharmony_ci
3168c2ecf20Sopenharmony_ci	/*
3178c2ecf20Sopenharmony_ci	 *	Fill in the IPv6 header
3188c2ecf20Sopenharmony_ci	 */
3198c2ecf20Sopenharmony_ci	if (np)
3208c2ecf20Sopenharmony_ci		hlimit = np->hop_limit;
3218c2ecf20Sopenharmony_ci	if (hlimit < 0)
3228c2ecf20Sopenharmony_ci		hlimit = ip6_dst_hoplimit(dst);
3238c2ecf20Sopenharmony_ci
3248c2ecf20Sopenharmony_ci	ip6_flow_hdr(hdr, tclass, ip6_make_flowlabel(net, skb, fl6->flowlabel,
3258c2ecf20Sopenharmony_ci				ip6_autoflowlabel(net, np), fl6));
3268c2ecf20Sopenharmony_ci
3278c2ecf20Sopenharmony_ci	hdr->payload_len = htons(seg_len);
3288c2ecf20Sopenharmony_ci	hdr->nexthdr = proto;
3298c2ecf20Sopenharmony_ci	hdr->hop_limit = hlimit;
3308c2ecf20Sopenharmony_ci
3318c2ecf20Sopenharmony_ci	hdr->saddr = fl6->saddr;
3328c2ecf20Sopenharmony_ci	hdr->daddr = *first_hop;
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_ci	skb->protocol = htons(ETH_P_IPV6);
3358c2ecf20Sopenharmony_ci	skb->priority = priority;
3368c2ecf20Sopenharmony_ci	skb->mark = mark;
3378c2ecf20Sopenharmony_ci
3388c2ecf20Sopenharmony_ci	mtu = dst_mtu(dst);
3398c2ecf20Sopenharmony_ci	if ((skb->len <= mtu) || skb->ignore_df || skb_is_gso(skb)) {
3408c2ecf20Sopenharmony_ci		IP6_UPD_PO_STATS(net, ip6_dst_idev(skb_dst(skb)),
3418c2ecf20Sopenharmony_ci			      IPSTATS_MIB_OUT, skb->len);
3428c2ecf20Sopenharmony_ci
3438c2ecf20Sopenharmony_ci		/* if egress device is enslaved to an L3 master device pass the
3448c2ecf20Sopenharmony_ci		 * skb to its handler for processing
3458c2ecf20Sopenharmony_ci		 */
3468c2ecf20Sopenharmony_ci		skb = l3mdev_ip6_out((struct sock *)sk, skb);
3478c2ecf20Sopenharmony_ci		if (unlikely(!skb))
3488c2ecf20Sopenharmony_ci			return 0;
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_ci		/* hooks should never assume socket lock is held.
3518c2ecf20Sopenharmony_ci		 * we promote our socket to non const
3528c2ecf20Sopenharmony_ci		 */
3538c2ecf20Sopenharmony_ci		return NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_OUT,
3548c2ecf20Sopenharmony_ci			       net, (struct sock *)sk, skb, NULL, dst->dev,
3558c2ecf20Sopenharmony_ci			       dst_output);
3568c2ecf20Sopenharmony_ci	}
3578c2ecf20Sopenharmony_ci
3588c2ecf20Sopenharmony_ci	skb->dev = dst->dev;
3598c2ecf20Sopenharmony_ci	/* ipv6_local_error() does not require socket lock,
3608c2ecf20Sopenharmony_ci	 * we promote our socket to non const
3618c2ecf20Sopenharmony_ci	 */
3628c2ecf20Sopenharmony_ci	ipv6_local_error((struct sock *)sk, EMSGSIZE, fl6, mtu);
3638c2ecf20Sopenharmony_ci
3648c2ecf20Sopenharmony_ci	IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_FRAGFAILS);
3658c2ecf20Sopenharmony_ci	kfree_skb(skb);
3668c2ecf20Sopenharmony_ci	return -EMSGSIZE;
3678c2ecf20Sopenharmony_ci}
3688c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ip6_xmit);
3698c2ecf20Sopenharmony_ci
3708c2ecf20Sopenharmony_cistatic int ip6_call_ra_chain(struct sk_buff *skb, int sel)
3718c2ecf20Sopenharmony_ci{
3728c2ecf20Sopenharmony_ci	struct ip6_ra_chain *ra;
3738c2ecf20Sopenharmony_ci	struct sock *last = NULL;
3748c2ecf20Sopenharmony_ci
3758c2ecf20Sopenharmony_ci	read_lock(&ip6_ra_lock);
3768c2ecf20Sopenharmony_ci	for (ra = ip6_ra_chain; ra; ra = ra->next) {
3778c2ecf20Sopenharmony_ci		struct sock *sk = ra->sk;
3788c2ecf20Sopenharmony_ci		if (sk && ra->sel == sel &&
3798c2ecf20Sopenharmony_ci		    (!sk->sk_bound_dev_if ||
3808c2ecf20Sopenharmony_ci		     sk->sk_bound_dev_if == skb->dev->ifindex)) {
3818c2ecf20Sopenharmony_ci			struct ipv6_pinfo *np = inet6_sk(sk);
3828c2ecf20Sopenharmony_ci
3838c2ecf20Sopenharmony_ci			if (np && np->rtalert_isolate &&
3848c2ecf20Sopenharmony_ci			    !net_eq(sock_net(sk), dev_net(skb->dev))) {
3858c2ecf20Sopenharmony_ci				continue;
3868c2ecf20Sopenharmony_ci			}
3878c2ecf20Sopenharmony_ci			if (last) {
3888c2ecf20Sopenharmony_ci				struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC);
3898c2ecf20Sopenharmony_ci				if (skb2)
3908c2ecf20Sopenharmony_ci					rawv6_rcv(last, skb2);
3918c2ecf20Sopenharmony_ci			}
3928c2ecf20Sopenharmony_ci			last = sk;
3938c2ecf20Sopenharmony_ci		}
3948c2ecf20Sopenharmony_ci	}
3958c2ecf20Sopenharmony_ci
3968c2ecf20Sopenharmony_ci	if (last) {
3978c2ecf20Sopenharmony_ci		rawv6_rcv(last, skb);
3988c2ecf20Sopenharmony_ci		read_unlock(&ip6_ra_lock);
3998c2ecf20Sopenharmony_ci		return 1;
4008c2ecf20Sopenharmony_ci	}
4018c2ecf20Sopenharmony_ci	read_unlock(&ip6_ra_lock);
4028c2ecf20Sopenharmony_ci	return 0;
4038c2ecf20Sopenharmony_ci}
4048c2ecf20Sopenharmony_ci
4058c2ecf20Sopenharmony_cistatic int ip6_forward_proxy_check(struct sk_buff *skb)
4068c2ecf20Sopenharmony_ci{
4078c2ecf20Sopenharmony_ci	struct ipv6hdr *hdr = ipv6_hdr(skb);
4088c2ecf20Sopenharmony_ci	u8 nexthdr = hdr->nexthdr;
4098c2ecf20Sopenharmony_ci	__be16 frag_off;
4108c2ecf20Sopenharmony_ci	int offset;
4118c2ecf20Sopenharmony_ci
4128c2ecf20Sopenharmony_ci	if (ipv6_ext_hdr(nexthdr)) {
4138c2ecf20Sopenharmony_ci		offset = ipv6_skip_exthdr(skb, sizeof(*hdr), &nexthdr, &frag_off);
4148c2ecf20Sopenharmony_ci		if (offset < 0)
4158c2ecf20Sopenharmony_ci			return 0;
4168c2ecf20Sopenharmony_ci	} else
4178c2ecf20Sopenharmony_ci		offset = sizeof(struct ipv6hdr);
4188c2ecf20Sopenharmony_ci
4198c2ecf20Sopenharmony_ci	if (nexthdr == IPPROTO_ICMPV6) {
4208c2ecf20Sopenharmony_ci		struct icmp6hdr *icmp6;
4218c2ecf20Sopenharmony_ci
4228c2ecf20Sopenharmony_ci		if (!pskb_may_pull(skb, (skb_network_header(skb) +
4238c2ecf20Sopenharmony_ci					 offset + 1 - skb->data)))
4248c2ecf20Sopenharmony_ci			return 0;
4258c2ecf20Sopenharmony_ci
4268c2ecf20Sopenharmony_ci		icmp6 = (struct icmp6hdr *)(skb_network_header(skb) + offset);
4278c2ecf20Sopenharmony_ci
4288c2ecf20Sopenharmony_ci		switch (icmp6->icmp6_type) {
4298c2ecf20Sopenharmony_ci		case NDISC_ROUTER_SOLICITATION:
4308c2ecf20Sopenharmony_ci		case NDISC_ROUTER_ADVERTISEMENT:
4318c2ecf20Sopenharmony_ci		case NDISC_NEIGHBOUR_SOLICITATION:
4328c2ecf20Sopenharmony_ci		case NDISC_NEIGHBOUR_ADVERTISEMENT:
4338c2ecf20Sopenharmony_ci		case NDISC_REDIRECT:
4348c2ecf20Sopenharmony_ci			/* For reaction involving unicast neighbor discovery
4358c2ecf20Sopenharmony_ci			 * message destined to the proxied address, pass it to
4368c2ecf20Sopenharmony_ci			 * input function.
4378c2ecf20Sopenharmony_ci			 */
4388c2ecf20Sopenharmony_ci			return 1;
4398c2ecf20Sopenharmony_ci		default:
4408c2ecf20Sopenharmony_ci			break;
4418c2ecf20Sopenharmony_ci		}
4428c2ecf20Sopenharmony_ci	}
4438c2ecf20Sopenharmony_ci
4448c2ecf20Sopenharmony_ci	/*
4458c2ecf20Sopenharmony_ci	 * The proxying router can't forward traffic sent to a link-local
4468c2ecf20Sopenharmony_ci	 * address, so signal the sender and discard the packet. This
4478c2ecf20Sopenharmony_ci	 * behavior is clarified by the MIPv6 specification.
4488c2ecf20Sopenharmony_ci	 */
4498c2ecf20Sopenharmony_ci	if (ipv6_addr_type(&hdr->daddr) & IPV6_ADDR_LINKLOCAL) {
4508c2ecf20Sopenharmony_ci		dst_link_failure(skb);
4518c2ecf20Sopenharmony_ci		return -1;
4528c2ecf20Sopenharmony_ci	}
4538c2ecf20Sopenharmony_ci
4548c2ecf20Sopenharmony_ci	return 0;
4558c2ecf20Sopenharmony_ci}
4568c2ecf20Sopenharmony_ci
4578c2ecf20Sopenharmony_cistatic inline int ip6_forward_finish(struct net *net, struct sock *sk,
4588c2ecf20Sopenharmony_ci				     struct sk_buff *skb)
4598c2ecf20Sopenharmony_ci{
4608c2ecf20Sopenharmony_ci	struct dst_entry *dst = skb_dst(skb);
4618c2ecf20Sopenharmony_ci
4628c2ecf20Sopenharmony_ci	__IP6_INC_STATS(net, ip6_dst_idev(dst), IPSTATS_MIB_OUTFORWDATAGRAMS);
4638c2ecf20Sopenharmony_ci	__IP6_ADD_STATS(net, ip6_dst_idev(dst), IPSTATS_MIB_OUTOCTETS, skb->len);
4648c2ecf20Sopenharmony_ci
4658c2ecf20Sopenharmony_ci#ifdef CONFIG_NET_SWITCHDEV
4668c2ecf20Sopenharmony_ci	if (skb->offload_l3_fwd_mark) {
4678c2ecf20Sopenharmony_ci		consume_skb(skb);
4688c2ecf20Sopenharmony_ci		return 0;
4698c2ecf20Sopenharmony_ci	}
4708c2ecf20Sopenharmony_ci#endif
4718c2ecf20Sopenharmony_ci
4728c2ecf20Sopenharmony_ci	skb->tstamp = 0;
4738c2ecf20Sopenharmony_ci	return dst_output(net, sk, skb);
4748c2ecf20Sopenharmony_ci}
4758c2ecf20Sopenharmony_ci
4768c2ecf20Sopenharmony_cistatic bool ip6_pkt_too_big(const struct sk_buff *skb, unsigned int mtu)
4778c2ecf20Sopenharmony_ci{
4788c2ecf20Sopenharmony_ci	if (skb->len <= mtu)
4798c2ecf20Sopenharmony_ci		return false;
4808c2ecf20Sopenharmony_ci
4818c2ecf20Sopenharmony_ci	/* ipv6 conntrack defrag sets max_frag_size + ignore_df */
4828c2ecf20Sopenharmony_ci	if (IP6CB(skb)->frag_max_size && IP6CB(skb)->frag_max_size > mtu)
4838c2ecf20Sopenharmony_ci		return true;
4848c2ecf20Sopenharmony_ci
4858c2ecf20Sopenharmony_ci	if (skb->ignore_df)
4868c2ecf20Sopenharmony_ci		return false;
4878c2ecf20Sopenharmony_ci
4888c2ecf20Sopenharmony_ci	if (skb_is_gso(skb) && skb_gso_validate_network_len(skb, mtu))
4898c2ecf20Sopenharmony_ci		return false;
4908c2ecf20Sopenharmony_ci
4918c2ecf20Sopenharmony_ci	return true;
4928c2ecf20Sopenharmony_ci}
4938c2ecf20Sopenharmony_ci
4948c2ecf20Sopenharmony_ciint ip6_forward(struct sk_buff *skb)
4958c2ecf20Sopenharmony_ci{
4968c2ecf20Sopenharmony_ci	struct dst_entry *dst = skb_dst(skb);
4978c2ecf20Sopenharmony_ci	struct ipv6hdr *hdr = ipv6_hdr(skb);
4988c2ecf20Sopenharmony_ci	struct inet6_skb_parm *opt = IP6CB(skb);
4998c2ecf20Sopenharmony_ci	struct net *net = dev_net(dst->dev);
5008c2ecf20Sopenharmony_ci	struct inet6_dev *idev;
5018c2ecf20Sopenharmony_ci	u32 mtu;
5028c2ecf20Sopenharmony_ci
5038c2ecf20Sopenharmony_ci	idev = __in6_dev_get_safely(dev_get_by_index_rcu(net, IP6CB(skb)->iif));
5048c2ecf20Sopenharmony_ci	if (net->ipv6.devconf_all->forwarding == 0)
5058c2ecf20Sopenharmony_ci		goto error;
5068c2ecf20Sopenharmony_ci
5078c2ecf20Sopenharmony_ci	if (skb->pkt_type != PACKET_HOST)
5088c2ecf20Sopenharmony_ci		goto drop;
5098c2ecf20Sopenharmony_ci
5108c2ecf20Sopenharmony_ci	if (unlikely(skb->sk))
5118c2ecf20Sopenharmony_ci		goto drop;
5128c2ecf20Sopenharmony_ci
5138c2ecf20Sopenharmony_ci	if (skb_warn_if_lro(skb))
5148c2ecf20Sopenharmony_ci		goto drop;
5158c2ecf20Sopenharmony_ci
5168c2ecf20Sopenharmony_ci	if (!net->ipv6.devconf_all->disable_policy &&
5178c2ecf20Sopenharmony_ci	    (!idev || !idev->cnf.disable_policy) &&
5188c2ecf20Sopenharmony_ci	    !xfrm6_policy_check(NULL, XFRM_POLICY_FWD, skb)) {
5198c2ecf20Sopenharmony_ci		__IP6_INC_STATS(net, idev, IPSTATS_MIB_INDISCARDS);
5208c2ecf20Sopenharmony_ci		goto drop;
5218c2ecf20Sopenharmony_ci	}
5228c2ecf20Sopenharmony_ci
5238c2ecf20Sopenharmony_ci	skb_forward_csum(skb);
5248c2ecf20Sopenharmony_ci
5258c2ecf20Sopenharmony_ci	/*
5268c2ecf20Sopenharmony_ci	 *	We DO NOT make any processing on
5278c2ecf20Sopenharmony_ci	 *	RA packets, pushing them to user level AS IS
5288c2ecf20Sopenharmony_ci	 *	without ane WARRANTY that application will be able
5298c2ecf20Sopenharmony_ci	 *	to interpret them. The reason is that we
5308c2ecf20Sopenharmony_ci	 *	cannot make anything clever here.
5318c2ecf20Sopenharmony_ci	 *
5328c2ecf20Sopenharmony_ci	 *	We are not end-node, so that if packet contains
5338c2ecf20Sopenharmony_ci	 *	AH/ESP, we cannot make anything.
5348c2ecf20Sopenharmony_ci	 *	Defragmentation also would be mistake, RA packets
5358c2ecf20Sopenharmony_ci	 *	cannot be fragmented, because there is no warranty
5368c2ecf20Sopenharmony_ci	 *	that different fragments will go along one path. --ANK
5378c2ecf20Sopenharmony_ci	 */
5388c2ecf20Sopenharmony_ci	if (unlikely(opt->flags & IP6SKB_ROUTERALERT)) {
5398c2ecf20Sopenharmony_ci		if (ip6_call_ra_chain(skb, ntohs(opt->ra)))
5408c2ecf20Sopenharmony_ci			return 0;
5418c2ecf20Sopenharmony_ci	}
5428c2ecf20Sopenharmony_ci
5438c2ecf20Sopenharmony_ci	/*
5448c2ecf20Sopenharmony_ci	 *	check and decrement ttl
5458c2ecf20Sopenharmony_ci	 */
5468c2ecf20Sopenharmony_ci	if (hdr->hop_limit <= 1) {
5478c2ecf20Sopenharmony_ci		icmpv6_send(skb, ICMPV6_TIME_EXCEED, ICMPV6_EXC_HOPLIMIT, 0);
5488c2ecf20Sopenharmony_ci		__IP6_INC_STATS(net, idev, IPSTATS_MIB_INHDRERRORS);
5498c2ecf20Sopenharmony_ci
5508c2ecf20Sopenharmony_ci		kfree_skb(skb);
5518c2ecf20Sopenharmony_ci		return -ETIMEDOUT;
5528c2ecf20Sopenharmony_ci	}
5538c2ecf20Sopenharmony_ci
5548c2ecf20Sopenharmony_ci	/* XXX: idev->cnf.proxy_ndp? */
5558c2ecf20Sopenharmony_ci	if (net->ipv6.devconf_all->proxy_ndp &&
5568c2ecf20Sopenharmony_ci	    pneigh_lookup(&nd_tbl, net, &hdr->daddr, skb->dev, 0)) {
5578c2ecf20Sopenharmony_ci		int proxied = ip6_forward_proxy_check(skb);
5588c2ecf20Sopenharmony_ci		if (proxied > 0)
5598c2ecf20Sopenharmony_ci			return ip6_input(skb);
5608c2ecf20Sopenharmony_ci		else if (proxied < 0) {
5618c2ecf20Sopenharmony_ci			__IP6_INC_STATS(net, idev, IPSTATS_MIB_INDISCARDS);
5628c2ecf20Sopenharmony_ci			goto drop;
5638c2ecf20Sopenharmony_ci		}
5648c2ecf20Sopenharmony_ci	}
5658c2ecf20Sopenharmony_ci
5668c2ecf20Sopenharmony_ci	if (!xfrm6_route_forward(skb)) {
5678c2ecf20Sopenharmony_ci		__IP6_INC_STATS(net, idev, IPSTATS_MIB_INDISCARDS);
5688c2ecf20Sopenharmony_ci		goto drop;
5698c2ecf20Sopenharmony_ci	}
5708c2ecf20Sopenharmony_ci	dst = skb_dst(skb);
5718c2ecf20Sopenharmony_ci
5728c2ecf20Sopenharmony_ci	/* IPv6 specs say nothing about it, but it is clear that we cannot
5738c2ecf20Sopenharmony_ci	   send redirects to source routed frames.
5748c2ecf20Sopenharmony_ci	   We don't send redirects to frames decapsulated from IPsec.
5758c2ecf20Sopenharmony_ci	 */
5768c2ecf20Sopenharmony_ci	if (IP6CB(skb)->iif == dst->dev->ifindex &&
5778c2ecf20Sopenharmony_ci	    opt->srcrt == 0 && !skb_sec_path(skb)) {
5788c2ecf20Sopenharmony_ci		struct in6_addr *target = NULL;
5798c2ecf20Sopenharmony_ci		struct inet_peer *peer;
5808c2ecf20Sopenharmony_ci		struct rt6_info *rt;
5818c2ecf20Sopenharmony_ci
5828c2ecf20Sopenharmony_ci		/*
5838c2ecf20Sopenharmony_ci		 *	incoming and outgoing devices are the same
5848c2ecf20Sopenharmony_ci		 *	send a redirect.
5858c2ecf20Sopenharmony_ci		 */
5868c2ecf20Sopenharmony_ci
5878c2ecf20Sopenharmony_ci		rt = (struct rt6_info *) dst;
5888c2ecf20Sopenharmony_ci		if (rt->rt6i_flags & RTF_GATEWAY)
5898c2ecf20Sopenharmony_ci			target = &rt->rt6i_gateway;
5908c2ecf20Sopenharmony_ci		else
5918c2ecf20Sopenharmony_ci			target = &hdr->daddr;
5928c2ecf20Sopenharmony_ci
5938c2ecf20Sopenharmony_ci		peer = inet_getpeer_v6(net->ipv6.peers, &hdr->daddr, 1);
5948c2ecf20Sopenharmony_ci
5958c2ecf20Sopenharmony_ci		/* Limit redirects both by destination (here)
5968c2ecf20Sopenharmony_ci		   and by source (inside ndisc_send_redirect)
5978c2ecf20Sopenharmony_ci		 */
5988c2ecf20Sopenharmony_ci		if (inet_peer_xrlim_allow(peer, 1*HZ))
5998c2ecf20Sopenharmony_ci			ndisc_send_redirect(skb, target);
6008c2ecf20Sopenharmony_ci		if (peer)
6018c2ecf20Sopenharmony_ci			inet_putpeer(peer);
6028c2ecf20Sopenharmony_ci	} else {
6038c2ecf20Sopenharmony_ci		int addrtype = ipv6_addr_type(&hdr->saddr);
6048c2ecf20Sopenharmony_ci
6058c2ecf20Sopenharmony_ci		/* This check is security critical. */
6068c2ecf20Sopenharmony_ci		if (addrtype == IPV6_ADDR_ANY ||
6078c2ecf20Sopenharmony_ci		    addrtype & (IPV6_ADDR_MULTICAST | IPV6_ADDR_LOOPBACK))
6088c2ecf20Sopenharmony_ci			goto error;
6098c2ecf20Sopenharmony_ci		if (addrtype & IPV6_ADDR_LINKLOCAL) {
6108c2ecf20Sopenharmony_ci			icmpv6_send(skb, ICMPV6_DEST_UNREACH,
6118c2ecf20Sopenharmony_ci				    ICMPV6_NOT_NEIGHBOUR, 0);
6128c2ecf20Sopenharmony_ci			goto error;
6138c2ecf20Sopenharmony_ci		}
6148c2ecf20Sopenharmony_ci	}
6158c2ecf20Sopenharmony_ci
6168c2ecf20Sopenharmony_ci	mtu = ip6_dst_mtu_forward(dst);
6178c2ecf20Sopenharmony_ci	if (mtu < IPV6_MIN_MTU)
6188c2ecf20Sopenharmony_ci		mtu = IPV6_MIN_MTU;
6198c2ecf20Sopenharmony_ci
6208c2ecf20Sopenharmony_ci	if (ip6_pkt_too_big(skb, mtu)) {
6218c2ecf20Sopenharmony_ci		/* Again, force OUTPUT device used as source address */
6228c2ecf20Sopenharmony_ci		skb->dev = dst->dev;
6238c2ecf20Sopenharmony_ci		icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
6248c2ecf20Sopenharmony_ci		__IP6_INC_STATS(net, idev, IPSTATS_MIB_INTOOBIGERRORS);
6258c2ecf20Sopenharmony_ci		__IP6_INC_STATS(net, ip6_dst_idev(dst),
6268c2ecf20Sopenharmony_ci				IPSTATS_MIB_FRAGFAILS);
6278c2ecf20Sopenharmony_ci		kfree_skb(skb);
6288c2ecf20Sopenharmony_ci		return -EMSGSIZE;
6298c2ecf20Sopenharmony_ci	}
6308c2ecf20Sopenharmony_ci
6318c2ecf20Sopenharmony_ci	if (skb_cow(skb, dst->dev->hard_header_len)) {
6328c2ecf20Sopenharmony_ci		__IP6_INC_STATS(net, ip6_dst_idev(dst),
6338c2ecf20Sopenharmony_ci				IPSTATS_MIB_OUTDISCARDS);
6348c2ecf20Sopenharmony_ci		goto drop;
6358c2ecf20Sopenharmony_ci	}
6368c2ecf20Sopenharmony_ci
6378c2ecf20Sopenharmony_ci	hdr = ipv6_hdr(skb);
6388c2ecf20Sopenharmony_ci
6398c2ecf20Sopenharmony_ci	/* Mangling hops number delayed to point after skb COW */
6408c2ecf20Sopenharmony_ci
6418c2ecf20Sopenharmony_ci	hdr->hop_limit--;
6428c2ecf20Sopenharmony_ci
6438c2ecf20Sopenharmony_ci	return NF_HOOK(NFPROTO_IPV6, NF_INET_FORWARD,
6448c2ecf20Sopenharmony_ci		       net, NULL, skb, skb->dev, dst->dev,
6458c2ecf20Sopenharmony_ci		       ip6_forward_finish);
6468c2ecf20Sopenharmony_ci
6478c2ecf20Sopenharmony_cierror:
6488c2ecf20Sopenharmony_ci	__IP6_INC_STATS(net, idev, IPSTATS_MIB_INADDRERRORS);
6498c2ecf20Sopenharmony_cidrop:
6508c2ecf20Sopenharmony_ci	kfree_skb(skb);
6518c2ecf20Sopenharmony_ci	return -EINVAL;
6528c2ecf20Sopenharmony_ci}
6538c2ecf20Sopenharmony_ci
6548c2ecf20Sopenharmony_cistatic void ip6_copy_metadata(struct sk_buff *to, struct sk_buff *from)
6558c2ecf20Sopenharmony_ci{
6568c2ecf20Sopenharmony_ci	to->pkt_type = from->pkt_type;
6578c2ecf20Sopenharmony_ci	to->priority = from->priority;
6588c2ecf20Sopenharmony_ci	to->protocol = from->protocol;
6598c2ecf20Sopenharmony_ci	skb_dst_drop(to);
6608c2ecf20Sopenharmony_ci	skb_dst_set(to, dst_clone(skb_dst(from)));
6618c2ecf20Sopenharmony_ci	to->dev = from->dev;
6628c2ecf20Sopenharmony_ci	to->mark = from->mark;
6638c2ecf20Sopenharmony_ci
6648c2ecf20Sopenharmony_ci	skb_copy_hash(to, from);
6658c2ecf20Sopenharmony_ci
6668c2ecf20Sopenharmony_ci#ifdef CONFIG_NET_SCHED
6678c2ecf20Sopenharmony_ci	to->tc_index = from->tc_index;
6688c2ecf20Sopenharmony_ci#endif
6698c2ecf20Sopenharmony_ci	nf_copy(to, from);
6708c2ecf20Sopenharmony_ci	skb_ext_copy(to, from);
6718c2ecf20Sopenharmony_ci	skb_copy_secmark(to, from);
6728c2ecf20Sopenharmony_ci}
6738c2ecf20Sopenharmony_ci
6748c2ecf20Sopenharmony_ciint ip6_fraglist_init(struct sk_buff *skb, unsigned int hlen, u8 *prevhdr,
6758c2ecf20Sopenharmony_ci		      u8 nexthdr, __be32 frag_id,
6768c2ecf20Sopenharmony_ci		      struct ip6_fraglist_iter *iter)
6778c2ecf20Sopenharmony_ci{
6788c2ecf20Sopenharmony_ci	unsigned int first_len;
6798c2ecf20Sopenharmony_ci	struct frag_hdr *fh;
6808c2ecf20Sopenharmony_ci
6818c2ecf20Sopenharmony_ci	/* BUILD HEADER */
6828c2ecf20Sopenharmony_ci	*prevhdr = NEXTHDR_FRAGMENT;
6838c2ecf20Sopenharmony_ci	iter->tmp_hdr = kmemdup(skb_network_header(skb), hlen, GFP_ATOMIC);
6848c2ecf20Sopenharmony_ci	if (!iter->tmp_hdr)
6858c2ecf20Sopenharmony_ci		return -ENOMEM;
6868c2ecf20Sopenharmony_ci
6878c2ecf20Sopenharmony_ci	iter->frag = skb_shinfo(skb)->frag_list;
6888c2ecf20Sopenharmony_ci	skb_frag_list_init(skb);
6898c2ecf20Sopenharmony_ci
6908c2ecf20Sopenharmony_ci	iter->offset = 0;
6918c2ecf20Sopenharmony_ci	iter->hlen = hlen;
6928c2ecf20Sopenharmony_ci	iter->frag_id = frag_id;
6938c2ecf20Sopenharmony_ci	iter->nexthdr = nexthdr;
6948c2ecf20Sopenharmony_ci
6958c2ecf20Sopenharmony_ci	__skb_pull(skb, hlen);
6968c2ecf20Sopenharmony_ci	fh = __skb_push(skb, sizeof(struct frag_hdr));
6978c2ecf20Sopenharmony_ci	__skb_push(skb, hlen);
6988c2ecf20Sopenharmony_ci	skb_reset_network_header(skb);
6998c2ecf20Sopenharmony_ci	memcpy(skb_network_header(skb), iter->tmp_hdr, hlen);
7008c2ecf20Sopenharmony_ci
7018c2ecf20Sopenharmony_ci	fh->nexthdr = nexthdr;
7028c2ecf20Sopenharmony_ci	fh->reserved = 0;
7038c2ecf20Sopenharmony_ci	fh->frag_off = htons(IP6_MF);
7048c2ecf20Sopenharmony_ci	fh->identification = frag_id;
7058c2ecf20Sopenharmony_ci
7068c2ecf20Sopenharmony_ci	first_len = skb_pagelen(skb);
7078c2ecf20Sopenharmony_ci	skb->data_len = first_len - skb_headlen(skb);
7088c2ecf20Sopenharmony_ci	skb->len = first_len;
7098c2ecf20Sopenharmony_ci	ipv6_hdr(skb)->payload_len = htons(first_len - sizeof(struct ipv6hdr));
7108c2ecf20Sopenharmony_ci
7118c2ecf20Sopenharmony_ci	return 0;
7128c2ecf20Sopenharmony_ci}
7138c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ip6_fraglist_init);
7148c2ecf20Sopenharmony_ci
7158c2ecf20Sopenharmony_civoid ip6_fraglist_prepare(struct sk_buff *skb,
7168c2ecf20Sopenharmony_ci			  struct ip6_fraglist_iter *iter)
7178c2ecf20Sopenharmony_ci{
7188c2ecf20Sopenharmony_ci	struct sk_buff *frag = iter->frag;
7198c2ecf20Sopenharmony_ci	unsigned int hlen = iter->hlen;
7208c2ecf20Sopenharmony_ci	struct frag_hdr *fh;
7218c2ecf20Sopenharmony_ci
7228c2ecf20Sopenharmony_ci	frag->ip_summed = CHECKSUM_NONE;
7238c2ecf20Sopenharmony_ci	skb_reset_transport_header(frag);
7248c2ecf20Sopenharmony_ci	fh = __skb_push(frag, sizeof(struct frag_hdr));
7258c2ecf20Sopenharmony_ci	__skb_push(frag, hlen);
7268c2ecf20Sopenharmony_ci	skb_reset_network_header(frag);
7278c2ecf20Sopenharmony_ci	memcpy(skb_network_header(frag), iter->tmp_hdr, hlen);
7288c2ecf20Sopenharmony_ci	iter->offset += skb->len - hlen - sizeof(struct frag_hdr);
7298c2ecf20Sopenharmony_ci	fh->nexthdr = iter->nexthdr;
7308c2ecf20Sopenharmony_ci	fh->reserved = 0;
7318c2ecf20Sopenharmony_ci	fh->frag_off = htons(iter->offset);
7328c2ecf20Sopenharmony_ci	if (frag->next)
7338c2ecf20Sopenharmony_ci		fh->frag_off |= htons(IP6_MF);
7348c2ecf20Sopenharmony_ci	fh->identification = iter->frag_id;
7358c2ecf20Sopenharmony_ci	ipv6_hdr(frag)->payload_len = htons(frag->len - sizeof(struct ipv6hdr));
7368c2ecf20Sopenharmony_ci	ip6_copy_metadata(frag, skb);
7378c2ecf20Sopenharmony_ci}
7388c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ip6_fraglist_prepare);
7398c2ecf20Sopenharmony_ci
7408c2ecf20Sopenharmony_civoid ip6_frag_init(struct sk_buff *skb, unsigned int hlen, unsigned int mtu,
7418c2ecf20Sopenharmony_ci		   unsigned short needed_tailroom, int hdr_room, u8 *prevhdr,
7428c2ecf20Sopenharmony_ci		   u8 nexthdr, __be32 frag_id, struct ip6_frag_state *state)
7438c2ecf20Sopenharmony_ci{
7448c2ecf20Sopenharmony_ci	state->prevhdr = prevhdr;
7458c2ecf20Sopenharmony_ci	state->nexthdr = nexthdr;
7468c2ecf20Sopenharmony_ci	state->frag_id = frag_id;
7478c2ecf20Sopenharmony_ci
7488c2ecf20Sopenharmony_ci	state->hlen = hlen;
7498c2ecf20Sopenharmony_ci	state->mtu = mtu;
7508c2ecf20Sopenharmony_ci
7518c2ecf20Sopenharmony_ci	state->left = skb->len - hlen;	/* Space per frame */
7528c2ecf20Sopenharmony_ci	state->ptr = hlen;		/* Where to start from */
7538c2ecf20Sopenharmony_ci
7548c2ecf20Sopenharmony_ci	state->hroom = hdr_room;
7558c2ecf20Sopenharmony_ci	state->troom = needed_tailroom;
7568c2ecf20Sopenharmony_ci
7578c2ecf20Sopenharmony_ci	state->offset = 0;
7588c2ecf20Sopenharmony_ci}
7598c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ip6_frag_init);
7608c2ecf20Sopenharmony_ci
7618c2ecf20Sopenharmony_cistruct sk_buff *ip6_frag_next(struct sk_buff *skb, struct ip6_frag_state *state)
7628c2ecf20Sopenharmony_ci{
7638c2ecf20Sopenharmony_ci	u8 *prevhdr = state->prevhdr, *fragnexthdr_offset;
7648c2ecf20Sopenharmony_ci	struct sk_buff *frag;
7658c2ecf20Sopenharmony_ci	struct frag_hdr *fh;
7668c2ecf20Sopenharmony_ci	unsigned int len;
7678c2ecf20Sopenharmony_ci
7688c2ecf20Sopenharmony_ci	len = state->left;
7698c2ecf20Sopenharmony_ci	/* IF: it doesn't fit, use 'mtu' - the data space left */
7708c2ecf20Sopenharmony_ci	if (len > state->mtu)
7718c2ecf20Sopenharmony_ci		len = state->mtu;
7728c2ecf20Sopenharmony_ci	/* IF: we are not sending up to and including the packet end
7738c2ecf20Sopenharmony_ci	   then align the next start on an eight byte boundary */
7748c2ecf20Sopenharmony_ci	if (len < state->left)
7758c2ecf20Sopenharmony_ci		len &= ~7;
7768c2ecf20Sopenharmony_ci
7778c2ecf20Sopenharmony_ci	/* Allocate buffer */
7788c2ecf20Sopenharmony_ci	frag = alloc_skb(len + state->hlen + sizeof(struct frag_hdr) +
7798c2ecf20Sopenharmony_ci			 state->hroom + state->troom, GFP_ATOMIC);
7808c2ecf20Sopenharmony_ci	if (!frag)
7818c2ecf20Sopenharmony_ci		return ERR_PTR(-ENOMEM);
7828c2ecf20Sopenharmony_ci
7838c2ecf20Sopenharmony_ci	/*
7848c2ecf20Sopenharmony_ci	 *	Set up data on packet
7858c2ecf20Sopenharmony_ci	 */
7868c2ecf20Sopenharmony_ci
7878c2ecf20Sopenharmony_ci	ip6_copy_metadata(frag, skb);
7888c2ecf20Sopenharmony_ci	skb_reserve(frag, state->hroom);
7898c2ecf20Sopenharmony_ci	skb_put(frag, len + state->hlen + sizeof(struct frag_hdr));
7908c2ecf20Sopenharmony_ci	skb_reset_network_header(frag);
7918c2ecf20Sopenharmony_ci	fh = (struct frag_hdr *)(skb_network_header(frag) + state->hlen);
7928c2ecf20Sopenharmony_ci	frag->transport_header = (frag->network_header + state->hlen +
7938c2ecf20Sopenharmony_ci				  sizeof(struct frag_hdr));
7948c2ecf20Sopenharmony_ci
7958c2ecf20Sopenharmony_ci	/*
7968c2ecf20Sopenharmony_ci	 *	Charge the memory for the fragment to any owner
7978c2ecf20Sopenharmony_ci	 *	it might possess
7988c2ecf20Sopenharmony_ci	 */
7998c2ecf20Sopenharmony_ci	if (skb->sk)
8008c2ecf20Sopenharmony_ci		skb_set_owner_w(frag, skb->sk);
8018c2ecf20Sopenharmony_ci
8028c2ecf20Sopenharmony_ci	/*
8038c2ecf20Sopenharmony_ci	 *	Copy the packet header into the new buffer.
8048c2ecf20Sopenharmony_ci	 */
8058c2ecf20Sopenharmony_ci	skb_copy_from_linear_data(skb, skb_network_header(frag), state->hlen);
8068c2ecf20Sopenharmony_ci
8078c2ecf20Sopenharmony_ci	fragnexthdr_offset = skb_network_header(frag);
8088c2ecf20Sopenharmony_ci	fragnexthdr_offset += prevhdr - skb_network_header(skb);
8098c2ecf20Sopenharmony_ci	*fragnexthdr_offset = NEXTHDR_FRAGMENT;
8108c2ecf20Sopenharmony_ci
8118c2ecf20Sopenharmony_ci	/*
8128c2ecf20Sopenharmony_ci	 *	Build fragment header.
8138c2ecf20Sopenharmony_ci	 */
8148c2ecf20Sopenharmony_ci	fh->nexthdr = state->nexthdr;
8158c2ecf20Sopenharmony_ci	fh->reserved = 0;
8168c2ecf20Sopenharmony_ci	fh->identification = state->frag_id;
8178c2ecf20Sopenharmony_ci
8188c2ecf20Sopenharmony_ci	/*
8198c2ecf20Sopenharmony_ci	 *	Copy a block of the IP datagram.
8208c2ecf20Sopenharmony_ci	 */
8218c2ecf20Sopenharmony_ci	BUG_ON(skb_copy_bits(skb, state->ptr, skb_transport_header(frag),
8228c2ecf20Sopenharmony_ci			     len));
8238c2ecf20Sopenharmony_ci	state->left -= len;
8248c2ecf20Sopenharmony_ci
8258c2ecf20Sopenharmony_ci	fh->frag_off = htons(state->offset);
8268c2ecf20Sopenharmony_ci	if (state->left > 0)
8278c2ecf20Sopenharmony_ci		fh->frag_off |= htons(IP6_MF);
8288c2ecf20Sopenharmony_ci	ipv6_hdr(frag)->payload_len = htons(frag->len - sizeof(struct ipv6hdr));
8298c2ecf20Sopenharmony_ci
8308c2ecf20Sopenharmony_ci	state->ptr += len;
8318c2ecf20Sopenharmony_ci	state->offset += len;
8328c2ecf20Sopenharmony_ci
8338c2ecf20Sopenharmony_ci	return frag;
8348c2ecf20Sopenharmony_ci}
8358c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ip6_frag_next);
8368c2ecf20Sopenharmony_ci
8378c2ecf20Sopenharmony_ciint ip6_fragment(struct net *net, struct sock *sk, struct sk_buff *skb,
8388c2ecf20Sopenharmony_ci		 int (*output)(struct net *, struct sock *, struct sk_buff *))
8398c2ecf20Sopenharmony_ci{
8408c2ecf20Sopenharmony_ci	struct sk_buff *frag;
8418c2ecf20Sopenharmony_ci	struct rt6_info *rt = (struct rt6_info *)skb_dst(skb);
8428c2ecf20Sopenharmony_ci	struct ipv6_pinfo *np = skb->sk && !dev_recursion_level() ?
8438c2ecf20Sopenharmony_ci				inet6_sk(skb->sk) : NULL;
8448c2ecf20Sopenharmony_ci	struct ip6_frag_state state;
8458c2ecf20Sopenharmony_ci	unsigned int mtu, hlen, nexthdr_offset;
8468c2ecf20Sopenharmony_ci	ktime_t tstamp = skb->tstamp;
8478c2ecf20Sopenharmony_ci	int hroom, err = 0;
8488c2ecf20Sopenharmony_ci	__be32 frag_id;
8498c2ecf20Sopenharmony_ci	u8 *prevhdr, nexthdr = 0;
8508c2ecf20Sopenharmony_ci
8518c2ecf20Sopenharmony_ci	err = ip6_find_1stfragopt(skb, &prevhdr);
8528c2ecf20Sopenharmony_ci	if (err < 0)
8538c2ecf20Sopenharmony_ci		goto fail;
8548c2ecf20Sopenharmony_ci	hlen = err;
8558c2ecf20Sopenharmony_ci	nexthdr = *prevhdr;
8568c2ecf20Sopenharmony_ci	nexthdr_offset = prevhdr - skb_network_header(skb);
8578c2ecf20Sopenharmony_ci
8588c2ecf20Sopenharmony_ci	mtu = ip6_skb_dst_mtu(skb);
8598c2ecf20Sopenharmony_ci
8608c2ecf20Sopenharmony_ci	/* We must not fragment if the socket is set to force MTU discovery
8618c2ecf20Sopenharmony_ci	 * or if the skb it not generated by a local socket.
8628c2ecf20Sopenharmony_ci	 */
8638c2ecf20Sopenharmony_ci	if (unlikely(!skb->ignore_df && skb->len > mtu))
8648c2ecf20Sopenharmony_ci		goto fail_toobig;
8658c2ecf20Sopenharmony_ci
8668c2ecf20Sopenharmony_ci	if (IP6CB(skb)->frag_max_size) {
8678c2ecf20Sopenharmony_ci		if (IP6CB(skb)->frag_max_size > mtu)
8688c2ecf20Sopenharmony_ci			goto fail_toobig;
8698c2ecf20Sopenharmony_ci
8708c2ecf20Sopenharmony_ci		/* don't send fragments larger than what we received */
8718c2ecf20Sopenharmony_ci		mtu = IP6CB(skb)->frag_max_size;
8728c2ecf20Sopenharmony_ci		if (mtu < IPV6_MIN_MTU)
8738c2ecf20Sopenharmony_ci			mtu = IPV6_MIN_MTU;
8748c2ecf20Sopenharmony_ci	}
8758c2ecf20Sopenharmony_ci
8768c2ecf20Sopenharmony_ci	if (np && np->frag_size < mtu) {
8778c2ecf20Sopenharmony_ci		if (np->frag_size)
8788c2ecf20Sopenharmony_ci			mtu = np->frag_size;
8798c2ecf20Sopenharmony_ci	}
8808c2ecf20Sopenharmony_ci	if (mtu < hlen + sizeof(struct frag_hdr) + 8)
8818c2ecf20Sopenharmony_ci		goto fail_toobig;
8828c2ecf20Sopenharmony_ci	mtu -= hlen + sizeof(struct frag_hdr);
8838c2ecf20Sopenharmony_ci
8848c2ecf20Sopenharmony_ci	frag_id = ipv6_select_ident(net, &ipv6_hdr(skb)->daddr,
8858c2ecf20Sopenharmony_ci				    &ipv6_hdr(skb)->saddr);
8868c2ecf20Sopenharmony_ci
8878c2ecf20Sopenharmony_ci	if (skb->ip_summed == CHECKSUM_PARTIAL &&
8888c2ecf20Sopenharmony_ci	    (err = skb_checksum_help(skb)))
8898c2ecf20Sopenharmony_ci		goto fail;
8908c2ecf20Sopenharmony_ci
8918c2ecf20Sopenharmony_ci	prevhdr = skb_network_header(skb) + nexthdr_offset;
8928c2ecf20Sopenharmony_ci	hroom = LL_RESERVED_SPACE(rt->dst.dev);
8938c2ecf20Sopenharmony_ci	if (skb_has_frag_list(skb)) {
8948c2ecf20Sopenharmony_ci		unsigned int first_len = skb_pagelen(skb);
8958c2ecf20Sopenharmony_ci		struct ip6_fraglist_iter iter;
8968c2ecf20Sopenharmony_ci		struct sk_buff *frag2;
8978c2ecf20Sopenharmony_ci
8988c2ecf20Sopenharmony_ci		if (first_len - hlen > mtu ||
8998c2ecf20Sopenharmony_ci		    ((first_len - hlen) & 7) ||
9008c2ecf20Sopenharmony_ci		    skb_cloned(skb) ||
9018c2ecf20Sopenharmony_ci		    skb_headroom(skb) < (hroom + sizeof(struct frag_hdr)))
9028c2ecf20Sopenharmony_ci			goto slow_path;
9038c2ecf20Sopenharmony_ci
9048c2ecf20Sopenharmony_ci		skb_walk_frags(skb, frag) {
9058c2ecf20Sopenharmony_ci			/* Correct geometry. */
9068c2ecf20Sopenharmony_ci			if (frag->len > mtu ||
9078c2ecf20Sopenharmony_ci			    ((frag->len & 7) && frag->next) ||
9088c2ecf20Sopenharmony_ci			    skb_headroom(frag) < (hlen + hroom + sizeof(struct frag_hdr)))
9098c2ecf20Sopenharmony_ci				goto slow_path_clean;
9108c2ecf20Sopenharmony_ci
9118c2ecf20Sopenharmony_ci			/* Partially cloned skb? */
9128c2ecf20Sopenharmony_ci			if (skb_shared(frag))
9138c2ecf20Sopenharmony_ci				goto slow_path_clean;
9148c2ecf20Sopenharmony_ci
9158c2ecf20Sopenharmony_ci			BUG_ON(frag->sk);
9168c2ecf20Sopenharmony_ci			if (skb->sk) {
9178c2ecf20Sopenharmony_ci				frag->sk = skb->sk;
9188c2ecf20Sopenharmony_ci				frag->destructor = sock_wfree;
9198c2ecf20Sopenharmony_ci			}
9208c2ecf20Sopenharmony_ci			skb->truesize -= frag->truesize;
9218c2ecf20Sopenharmony_ci		}
9228c2ecf20Sopenharmony_ci
9238c2ecf20Sopenharmony_ci		err = ip6_fraglist_init(skb, hlen, prevhdr, nexthdr, frag_id,
9248c2ecf20Sopenharmony_ci					&iter);
9258c2ecf20Sopenharmony_ci		if (err < 0)
9268c2ecf20Sopenharmony_ci			goto fail;
9278c2ecf20Sopenharmony_ci
9288c2ecf20Sopenharmony_ci		/* We prevent @rt from being freed. */
9298c2ecf20Sopenharmony_ci		rcu_read_lock();
9308c2ecf20Sopenharmony_ci
9318c2ecf20Sopenharmony_ci		for (;;) {
9328c2ecf20Sopenharmony_ci			/* Prepare header of the next frame,
9338c2ecf20Sopenharmony_ci			 * before previous one went down. */
9348c2ecf20Sopenharmony_ci			if (iter.frag)
9358c2ecf20Sopenharmony_ci				ip6_fraglist_prepare(skb, &iter);
9368c2ecf20Sopenharmony_ci
9378c2ecf20Sopenharmony_ci			skb->tstamp = tstamp;
9388c2ecf20Sopenharmony_ci			err = output(net, sk, skb);
9398c2ecf20Sopenharmony_ci			if (!err)
9408c2ecf20Sopenharmony_ci				IP6_INC_STATS(net, ip6_dst_idev(&rt->dst),
9418c2ecf20Sopenharmony_ci					      IPSTATS_MIB_FRAGCREATES);
9428c2ecf20Sopenharmony_ci
9438c2ecf20Sopenharmony_ci			if (err || !iter.frag)
9448c2ecf20Sopenharmony_ci				break;
9458c2ecf20Sopenharmony_ci
9468c2ecf20Sopenharmony_ci			skb = ip6_fraglist_next(&iter);
9478c2ecf20Sopenharmony_ci		}
9488c2ecf20Sopenharmony_ci
9498c2ecf20Sopenharmony_ci		kfree(iter.tmp_hdr);
9508c2ecf20Sopenharmony_ci
9518c2ecf20Sopenharmony_ci		if (err == 0) {
9528c2ecf20Sopenharmony_ci			IP6_INC_STATS(net, ip6_dst_idev(&rt->dst),
9538c2ecf20Sopenharmony_ci				      IPSTATS_MIB_FRAGOKS);
9548c2ecf20Sopenharmony_ci			rcu_read_unlock();
9558c2ecf20Sopenharmony_ci			return 0;
9568c2ecf20Sopenharmony_ci		}
9578c2ecf20Sopenharmony_ci
9588c2ecf20Sopenharmony_ci		kfree_skb_list(iter.frag);
9598c2ecf20Sopenharmony_ci
9608c2ecf20Sopenharmony_ci		IP6_INC_STATS(net, ip6_dst_idev(&rt->dst),
9618c2ecf20Sopenharmony_ci			      IPSTATS_MIB_FRAGFAILS);
9628c2ecf20Sopenharmony_ci		rcu_read_unlock();
9638c2ecf20Sopenharmony_ci		return err;
9648c2ecf20Sopenharmony_ci
9658c2ecf20Sopenharmony_cislow_path_clean:
9668c2ecf20Sopenharmony_ci		skb_walk_frags(skb, frag2) {
9678c2ecf20Sopenharmony_ci			if (frag2 == frag)
9688c2ecf20Sopenharmony_ci				break;
9698c2ecf20Sopenharmony_ci			frag2->sk = NULL;
9708c2ecf20Sopenharmony_ci			frag2->destructor = NULL;
9718c2ecf20Sopenharmony_ci			skb->truesize += frag2->truesize;
9728c2ecf20Sopenharmony_ci		}
9738c2ecf20Sopenharmony_ci	}
9748c2ecf20Sopenharmony_ci
9758c2ecf20Sopenharmony_cislow_path:
9768c2ecf20Sopenharmony_ci	/*
9778c2ecf20Sopenharmony_ci	 *	Fragment the datagram.
9788c2ecf20Sopenharmony_ci	 */
9798c2ecf20Sopenharmony_ci
9808c2ecf20Sopenharmony_ci	ip6_frag_init(skb, hlen, mtu, rt->dst.dev->needed_tailroom,
9818c2ecf20Sopenharmony_ci		      LL_RESERVED_SPACE(rt->dst.dev), prevhdr, nexthdr, frag_id,
9828c2ecf20Sopenharmony_ci		      &state);
9838c2ecf20Sopenharmony_ci
9848c2ecf20Sopenharmony_ci	/*
9858c2ecf20Sopenharmony_ci	 *	Keep copying data until we run out.
9868c2ecf20Sopenharmony_ci	 */
9878c2ecf20Sopenharmony_ci
9888c2ecf20Sopenharmony_ci	while (state.left > 0) {
9898c2ecf20Sopenharmony_ci		frag = ip6_frag_next(skb, &state);
9908c2ecf20Sopenharmony_ci		if (IS_ERR(frag)) {
9918c2ecf20Sopenharmony_ci			err = PTR_ERR(frag);
9928c2ecf20Sopenharmony_ci			goto fail;
9938c2ecf20Sopenharmony_ci		}
9948c2ecf20Sopenharmony_ci
9958c2ecf20Sopenharmony_ci		/*
9968c2ecf20Sopenharmony_ci		 *	Put this fragment into the sending queue.
9978c2ecf20Sopenharmony_ci		 */
9988c2ecf20Sopenharmony_ci		frag->tstamp = tstamp;
9998c2ecf20Sopenharmony_ci		err = output(net, sk, frag);
10008c2ecf20Sopenharmony_ci		if (err)
10018c2ecf20Sopenharmony_ci			goto fail;
10028c2ecf20Sopenharmony_ci
10038c2ecf20Sopenharmony_ci		IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)),
10048c2ecf20Sopenharmony_ci			      IPSTATS_MIB_FRAGCREATES);
10058c2ecf20Sopenharmony_ci	}
10068c2ecf20Sopenharmony_ci	IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)),
10078c2ecf20Sopenharmony_ci		      IPSTATS_MIB_FRAGOKS);
10088c2ecf20Sopenharmony_ci	consume_skb(skb);
10098c2ecf20Sopenharmony_ci	return err;
10108c2ecf20Sopenharmony_ci
10118c2ecf20Sopenharmony_cifail_toobig:
10128c2ecf20Sopenharmony_ci	if (skb->sk && dst_allfrag(skb_dst(skb)))
10138c2ecf20Sopenharmony_ci		sk_nocaps_add(skb->sk, NETIF_F_GSO_MASK);
10148c2ecf20Sopenharmony_ci
10158c2ecf20Sopenharmony_ci	icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
10168c2ecf20Sopenharmony_ci	err = -EMSGSIZE;
10178c2ecf20Sopenharmony_ci
10188c2ecf20Sopenharmony_cifail:
10198c2ecf20Sopenharmony_ci	IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)),
10208c2ecf20Sopenharmony_ci		      IPSTATS_MIB_FRAGFAILS);
10218c2ecf20Sopenharmony_ci	kfree_skb(skb);
10228c2ecf20Sopenharmony_ci	return err;
10238c2ecf20Sopenharmony_ci}
10248c2ecf20Sopenharmony_ci
10258c2ecf20Sopenharmony_cistatic inline int ip6_rt_check(const struct rt6key *rt_key,
10268c2ecf20Sopenharmony_ci			       const struct in6_addr *fl_addr,
10278c2ecf20Sopenharmony_ci			       const struct in6_addr *addr_cache)
10288c2ecf20Sopenharmony_ci{
10298c2ecf20Sopenharmony_ci	return (rt_key->plen != 128 || !ipv6_addr_equal(fl_addr, &rt_key->addr)) &&
10308c2ecf20Sopenharmony_ci		(!addr_cache || !ipv6_addr_equal(fl_addr, addr_cache));
10318c2ecf20Sopenharmony_ci}
10328c2ecf20Sopenharmony_ci
10338c2ecf20Sopenharmony_cistatic struct dst_entry *ip6_sk_dst_check(struct sock *sk,
10348c2ecf20Sopenharmony_ci					  struct dst_entry *dst,
10358c2ecf20Sopenharmony_ci					  const struct flowi6 *fl6)
10368c2ecf20Sopenharmony_ci{
10378c2ecf20Sopenharmony_ci	struct ipv6_pinfo *np = inet6_sk(sk);
10388c2ecf20Sopenharmony_ci	struct rt6_info *rt;
10398c2ecf20Sopenharmony_ci
10408c2ecf20Sopenharmony_ci	if (!dst)
10418c2ecf20Sopenharmony_ci		goto out;
10428c2ecf20Sopenharmony_ci
10438c2ecf20Sopenharmony_ci	if (dst->ops->family != AF_INET6) {
10448c2ecf20Sopenharmony_ci		dst_release(dst);
10458c2ecf20Sopenharmony_ci		return NULL;
10468c2ecf20Sopenharmony_ci	}
10478c2ecf20Sopenharmony_ci
10488c2ecf20Sopenharmony_ci	rt = (struct rt6_info *)dst;
10498c2ecf20Sopenharmony_ci	/* Yes, checking route validity in not connected
10508c2ecf20Sopenharmony_ci	 * case is not very simple. Take into account,
10518c2ecf20Sopenharmony_ci	 * that we do not support routing by source, TOS,
10528c2ecf20Sopenharmony_ci	 * and MSG_DONTROUTE		--ANK (980726)
10538c2ecf20Sopenharmony_ci	 *
10548c2ecf20Sopenharmony_ci	 * 1. ip6_rt_check(): If route was host route,
10558c2ecf20Sopenharmony_ci	 *    check that cached destination is current.
10568c2ecf20Sopenharmony_ci	 *    If it is network route, we still may
10578c2ecf20Sopenharmony_ci	 *    check its validity using saved pointer
10588c2ecf20Sopenharmony_ci	 *    to the last used address: daddr_cache.
10598c2ecf20Sopenharmony_ci	 *    We do not want to save whole address now,
10608c2ecf20Sopenharmony_ci	 *    (because main consumer of this service
10618c2ecf20Sopenharmony_ci	 *    is tcp, which has not this problem),
10628c2ecf20Sopenharmony_ci	 *    so that the last trick works only on connected
10638c2ecf20Sopenharmony_ci	 *    sockets.
10648c2ecf20Sopenharmony_ci	 * 2. oif also should be the same.
10658c2ecf20Sopenharmony_ci	 */
10668c2ecf20Sopenharmony_ci	if (ip6_rt_check(&rt->rt6i_dst, &fl6->daddr, np->daddr_cache) ||
10678c2ecf20Sopenharmony_ci#ifdef CONFIG_IPV6_SUBTREES
10688c2ecf20Sopenharmony_ci	    ip6_rt_check(&rt->rt6i_src, &fl6->saddr, np->saddr_cache) ||
10698c2ecf20Sopenharmony_ci#endif
10708c2ecf20Sopenharmony_ci	   (!(fl6->flowi6_flags & FLOWI_FLAG_SKIP_NH_OIF) &&
10718c2ecf20Sopenharmony_ci	      (fl6->flowi6_oif && fl6->flowi6_oif != dst->dev->ifindex))) {
10728c2ecf20Sopenharmony_ci		dst_release(dst);
10738c2ecf20Sopenharmony_ci		dst = NULL;
10748c2ecf20Sopenharmony_ci	}
10758c2ecf20Sopenharmony_ci
10768c2ecf20Sopenharmony_ciout:
10778c2ecf20Sopenharmony_ci	return dst;
10788c2ecf20Sopenharmony_ci}
10798c2ecf20Sopenharmony_ci
10808c2ecf20Sopenharmony_cistatic int ip6_dst_lookup_tail(struct net *net, const struct sock *sk,
10818c2ecf20Sopenharmony_ci			       struct dst_entry **dst, struct flowi6 *fl6)
10828c2ecf20Sopenharmony_ci{
10838c2ecf20Sopenharmony_ci#ifdef CONFIG_IPV6_OPTIMISTIC_DAD
10848c2ecf20Sopenharmony_ci	struct neighbour *n;
10858c2ecf20Sopenharmony_ci	struct rt6_info *rt;
10868c2ecf20Sopenharmony_ci#endif
10878c2ecf20Sopenharmony_ci	int err;
10888c2ecf20Sopenharmony_ci	int flags = 0;
10898c2ecf20Sopenharmony_ci
10908c2ecf20Sopenharmony_ci	/* The correct way to handle this would be to do
10918c2ecf20Sopenharmony_ci	 * ip6_route_get_saddr, and then ip6_route_output; however,
10928c2ecf20Sopenharmony_ci	 * the route-specific preferred source forces the
10938c2ecf20Sopenharmony_ci	 * ip6_route_output call _before_ ip6_route_get_saddr.
10948c2ecf20Sopenharmony_ci	 *
10958c2ecf20Sopenharmony_ci	 * In source specific routing (no src=any default route),
10968c2ecf20Sopenharmony_ci	 * ip6_route_output will fail given src=any saddr, though, so
10978c2ecf20Sopenharmony_ci	 * that's why we try it again later.
10988c2ecf20Sopenharmony_ci	 */
10998c2ecf20Sopenharmony_ci	if (ipv6_addr_any(&fl6->saddr) && (!*dst || !(*dst)->error)) {
11008c2ecf20Sopenharmony_ci		struct fib6_info *from;
11018c2ecf20Sopenharmony_ci		struct rt6_info *rt;
11028c2ecf20Sopenharmony_ci		bool had_dst = *dst != NULL;
11038c2ecf20Sopenharmony_ci
11048c2ecf20Sopenharmony_ci		if (!had_dst)
11058c2ecf20Sopenharmony_ci			*dst = ip6_route_output(net, sk, fl6);
11068c2ecf20Sopenharmony_ci		rt = (*dst)->error ? NULL : (struct rt6_info *)*dst;
11078c2ecf20Sopenharmony_ci
11088c2ecf20Sopenharmony_ci		rcu_read_lock();
11098c2ecf20Sopenharmony_ci		from = rt ? rcu_dereference(rt->from) : NULL;
11108c2ecf20Sopenharmony_ci		err = ip6_route_get_saddr(net, from, &fl6->daddr,
11118c2ecf20Sopenharmony_ci					  sk ? inet6_sk(sk)->srcprefs : 0,
11128c2ecf20Sopenharmony_ci					  &fl6->saddr);
11138c2ecf20Sopenharmony_ci		rcu_read_unlock();
11148c2ecf20Sopenharmony_ci
11158c2ecf20Sopenharmony_ci		if (err)
11168c2ecf20Sopenharmony_ci			goto out_err_release;
11178c2ecf20Sopenharmony_ci
11188c2ecf20Sopenharmony_ci		/* If we had an erroneous initial result, pretend it
11198c2ecf20Sopenharmony_ci		 * never existed and let the SA-enabled version take
11208c2ecf20Sopenharmony_ci		 * over.
11218c2ecf20Sopenharmony_ci		 */
11228c2ecf20Sopenharmony_ci		if (!had_dst && (*dst)->error) {
11238c2ecf20Sopenharmony_ci			dst_release(*dst);
11248c2ecf20Sopenharmony_ci			*dst = NULL;
11258c2ecf20Sopenharmony_ci		}
11268c2ecf20Sopenharmony_ci
11278c2ecf20Sopenharmony_ci		if (fl6->flowi6_oif)
11288c2ecf20Sopenharmony_ci			flags |= RT6_LOOKUP_F_IFACE;
11298c2ecf20Sopenharmony_ci	}
11308c2ecf20Sopenharmony_ci
11318c2ecf20Sopenharmony_ci	if (!*dst)
11328c2ecf20Sopenharmony_ci		*dst = ip6_route_output_flags(net, sk, fl6, flags);
11338c2ecf20Sopenharmony_ci
11348c2ecf20Sopenharmony_ci	err = (*dst)->error;
11358c2ecf20Sopenharmony_ci	if (err)
11368c2ecf20Sopenharmony_ci		goto out_err_release;
11378c2ecf20Sopenharmony_ci
11388c2ecf20Sopenharmony_ci#ifdef CONFIG_IPV6_OPTIMISTIC_DAD
11398c2ecf20Sopenharmony_ci	/*
11408c2ecf20Sopenharmony_ci	 * Here if the dst entry we've looked up
11418c2ecf20Sopenharmony_ci	 * has a neighbour entry that is in the INCOMPLETE
11428c2ecf20Sopenharmony_ci	 * state and the src address from the flow is
11438c2ecf20Sopenharmony_ci	 * marked as OPTIMISTIC, we release the found
11448c2ecf20Sopenharmony_ci	 * dst entry and replace it instead with the
11458c2ecf20Sopenharmony_ci	 * dst entry of the nexthop router
11468c2ecf20Sopenharmony_ci	 */
11478c2ecf20Sopenharmony_ci	rt = (struct rt6_info *) *dst;
11488c2ecf20Sopenharmony_ci	rcu_read_lock_bh();
11498c2ecf20Sopenharmony_ci	n = __ipv6_neigh_lookup_noref(rt->dst.dev,
11508c2ecf20Sopenharmony_ci				      rt6_nexthop(rt, &fl6->daddr));
11518c2ecf20Sopenharmony_ci	err = n && !(n->nud_state & NUD_VALID) ? -EINVAL : 0;
11528c2ecf20Sopenharmony_ci	rcu_read_unlock_bh();
11538c2ecf20Sopenharmony_ci
11548c2ecf20Sopenharmony_ci	if (err) {
11558c2ecf20Sopenharmony_ci		struct inet6_ifaddr *ifp;
11568c2ecf20Sopenharmony_ci		struct flowi6 fl_gw6;
11578c2ecf20Sopenharmony_ci		int redirect;
11588c2ecf20Sopenharmony_ci
11598c2ecf20Sopenharmony_ci		ifp = ipv6_get_ifaddr(net, &fl6->saddr,
11608c2ecf20Sopenharmony_ci				      (*dst)->dev, 1);
11618c2ecf20Sopenharmony_ci
11628c2ecf20Sopenharmony_ci		redirect = (ifp && ifp->flags & IFA_F_OPTIMISTIC);
11638c2ecf20Sopenharmony_ci		if (ifp)
11648c2ecf20Sopenharmony_ci			in6_ifa_put(ifp);
11658c2ecf20Sopenharmony_ci
11668c2ecf20Sopenharmony_ci		if (redirect) {
11678c2ecf20Sopenharmony_ci			/*
11688c2ecf20Sopenharmony_ci			 * We need to get the dst entry for the
11698c2ecf20Sopenharmony_ci			 * default router instead
11708c2ecf20Sopenharmony_ci			 */
11718c2ecf20Sopenharmony_ci			dst_release(*dst);
11728c2ecf20Sopenharmony_ci			memcpy(&fl_gw6, fl6, sizeof(struct flowi6));
11738c2ecf20Sopenharmony_ci			memset(&fl_gw6.daddr, 0, sizeof(struct in6_addr));
11748c2ecf20Sopenharmony_ci			*dst = ip6_route_output(net, sk, &fl_gw6);
11758c2ecf20Sopenharmony_ci			err = (*dst)->error;
11768c2ecf20Sopenharmony_ci			if (err)
11778c2ecf20Sopenharmony_ci				goto out_err_release;
11788c2ecf20Sopenharmony_ci		}
11798c2ecf20Sopenharmony_ci	}
11808c2ecf20Sopenharmony_ci#endif
11818c2ecf20Sopenharmony_ci	if (ipv6_addr_v4mapped(&fl6->saddr) &&
11828c2ecf20Sopenharmony_ci	    !(ipv6_addr_v4mapped(&fl6->daddr) || ipv6_addr_any(&fl6->daddr))) {
11838c2ecf20Sopenharmony_ci		err = -EAFNOSUPPORT;
11848c2ecf20Sopenharmony_ci		goto out_err_release;
11858c2ecf20Sopenharmony_ci	}
11868c2ecf20Sopenharmony_ci
11878c2ecf20Sopenharmony_ci	return 0;
11888c2ecf20Sopenharmony_ci
11898c2ecf20Sopenharmony_ciout_err_release:
11908c2ecf20Sopenharmony_ci	dst_release(*dst);
11918c2ecf20Sopenharmony_ci	*dst = NULL;
11928c2ecf20Sopenharmony_ci
11938c2ecf20Sopenharmony_ci	if (err == -ENETUNREACH)
11948c2ecf20Sopenharmony_ci		IP6_INC_STATS(net, NULL, IPSTATS_MIB_OUTNOROUTES);
11958c2ecf20Sopenharmony_ci	return err;
11968c2ecf20Sopenharmony_ci}
11978c2ecf20Sopenharmony_ci
11988c2ecf20Sopenharmony_ci/**
11998c2ecf20Sopenharmony_ci *	ip6_dst_lookup - perform route lookup on flow
12008c2ecf20Sopenharmony_ci *	@net: Network namespace to perform lookup in
12018c2ecf20Sopenharmony_ci *	@sk: socket which provides route info
12028c2ecf20Sopenharmony_ci *	@dst: pointer to dst_entry * for result
12038c2ecf20Sopenharmony_ci *	@fl6: flow to lookup
12048c2ecf20Sopenharmony_ci *
12058c2ecf20Sopenharmony_ci *	This function performs a route lookup on the given flow.
12068c2ecf20Sopenharmony_ci *
12078c2ecf20Sopenharmony_ci *	It returns zero on success, or a standard errno code on error.
12088c2ecf20Sopenharmony_ci */
12098c2ecf20Sopenharmony_ciint ip6_dst_lookup(struct net *net, struct sock *sk, struct dst_entry **dst,
12108c2ecf20Sopenharmony_ci		   struct flowi6 *fl6)
12118c2ecf20Sopenharmony_ci{
12128c2ecf20Sopenharmony_ci	*dst = NULL;
12138c2ecf20Sopenharmony_ci	return ip6_dst_lookup_tail(net, sk, dst, fl6);
12148c2ecf20Sopenharmony_ci}
12158c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(ip6_dst_lookup);
12168c2ecf20Sopenharmony_ci
12178c2ecf20Sopenharmony_ci/**
12188c2ecf20Sopenharmony_ci *	ip6_dst_lookup_flow - perform route lookup on flow with ipsec
12198c2ecf20Sopenharmony_ci *	@net: Network namespace to perform lookup in
12208c2ecf20Sopenharmony_ci *	@sk: socket which provides route info
12218c2ecf20Sopenharmony_ci *	@fl6: flow to lookup
12228c2ecf20Sopenharmony_ci *	@final_dst: final destination address for ipsec lookup
12238c2ecf20Sopenharmony_ci *
12248c2ecf20Sopenharmony_ci *	This function performs a route lookup on the given flow.
12258c2ecf20Sopenharmony_ci *
12268c2ecf20Sopenharmony_ci *	It returns a valid dst pointer on success, or a pointer encoded
12278c2ecf20Sopenharmony_ci *	error code.
12288c2ecf20Sopenharmony_ci */
12298c2ecf20Sopenharmony_cistruct dst_entry *ip6_dst_lookup_flow(struct net *net, const struct sock *sk, struct flowi6 *fl6,
12308c2ecf20Sopenharmony_ci				      const struct in6_addr *final_dst)
12318c2ecf20Sopenharmony_ci{
12328c2ecf20Sopenharmony_ci	struct dst_entry *dst = NULL;
12338c2ecf20Sopenharmony_ci	int err;
12348c2ecf20Sopenharmony_ci
12358c2ecf20Sopenharmony_ci	err = ip6_dst_lookup_tail(net, sk, &dst, fl6);
12368c2ecf20Sopenharmony_ci	if (err)
12378c2ecf20Sopenharmony_ci		return ERR_PTR(err);
12388c2ecf20Sopenharmony_ci	if (final_dst)
12398c2ecf20Sopenharmony_ci		fl6->daddr = *final_dst;
12408c2ecf20Sopenharmony_ci
12418c2ecf20Sopenharmony_ci	return xfrm_lookup_route(net, dst, flowi6_to_flowi(fl6), sk, 0);
12428c2ecf20Sopenharmony_ci}
12438c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(ip6_dst_lookup_flow);
12448c2ecf20Sopenharmony_ci
12458c2ecf20Sopenharmony_ci/**
12468c2ecf20Sopenharmony_ci *	ip6_sk_dst_lookup_flow - perform socket cached route lookup on flow
12478c2ecf20Sopenharmony_ci *	@sk: socket which provides the dst cache and route info
12488c2ecf20Sopenharmony_ci *	@fl6: flow to lookup
12498c2ecf20Sopenharmony_ci *	@final_dst: final destination address for ipsec lookup
12508c2ecf20Sopenharmony_ci *	@connected: whether @sk is connected or not
12518c2ecf20Sopenharmony_ci *
12528c2ecf20Sopenharmony_ci *	This function performs a route lookup on the given flow with the
12538c2ecf20Sopenharmony_ci *	possibility of using the cached route in the socket if it is valid.
12548c2ecf20Sopenharmony_ci *	It will take the socket dst lock when operating on the dst cache.
12558c2ecf20Sopenharmony_ci *	As a result, this function can only be used in process context.
12568c2ecf20Sopenharmony_ci *
12578c2ecf20Sopenharmony_ci *	In addition, for a connected socket, cache the dst in the socket
12588c2ecf20Sopenharmony_ci *	if the current cache is not valid.
12598c2ecf20Sopenharmony_ci *
12608c2ecf20Sopenharmony_ci *	It returns a valid dst pointer on success, or a pointer encoded
12618c2ecf20Sopenharmony_ci *	error code.
12628c2ecf20Sopenharmony_ci */
12638c2ecf20Sopenharmony_cistruct dst_entry *ip6_sk_dst_lookup_flow(struct sock *sk, struct flowi6 *fl6,
12648c2ecf20Sopenharmony_ci					 const struct in6_addr *final_dst,
12658c2ecf20Sopenharmony_ci					 bool connected)
12668c2ecf20Sopenharmony_ci{
12678c2ecf20Sopenharmony_ci	struct dst_entry *dst = sk_dst_check(sk, inet6_sk(sk)->dst_cookie);
12688c2ecf20Sopenharmony_ci
12698c2ecf20Sopenharmony_ci	dst = ip6_sk_dst_check(sk, dst, fl6);
12708c2ecf20Sopenharmony_ci	if (dst)
12718c2ecf20Sopenharmony_ci		return dst;
12728c2ecf20Sopenharmony_ci
12738c2ecf20Sopenharmony_ci	dst = ip6_dst_lookup_flow(sock_net(sk), sk, fl6, final_dst);
12748c2ecf20Sopenharmony_ci	if (connected && !IS_ERR(dst))
12758c2ecf20Sopenharmony_ci		ip6_sk_dst_store_flow(sk, dst_clone(dst), fl6);
12768c2ecf20Sopenharmony_ci
12778c2ecf20Sopenharmony_ci	return dst;
12788c2ecf20Sopenharmony_ci}
12798c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(ip6_sk_dst_lookup_flow);
12808c2ecf20Sopenharmony_ci
12818c2ecf20Sopenharmony_ci/**
12828c2ecf20Sopenharmony_ci *      ip6_dst_lookup_tunnel - perform route lookup on tunnel
12838c2ecf20Sopenharmony_ci *      @skb: Packet for which lookup is done
12848c2ecf20Sopenharmony_ci *      @dev: Tunnel device
12858c2ecf20Sopenharmony_ci *      @net: Network namespace of tunnel device
12868c2ecf20Sopenharmony_ci *      @sock: Socket which provides route info
12878c2ecf20Sopenharmony_ci *      @saddr: Memory to store the src ip address
12888c2ecf20Sopenharmony_ci *      @info: Tunnel information
12898c2ecf20Sopenharmony_ci *      @protocol: IP protocol
12908c2ecf20Sopenharmony_ci *      @use_cache: Flag to enable cache usage
12918c2ecf20Sopenharmony_ci *      This function performs a route lookup on a tunnel
12928c2ecf20Sopenharmony_ci *
12938c2ecf20Sopenharmony_ci *      It returns a valid dst pointer and stores src address to be used in
12948c2ecf20Sopenharmony_ci *      tunnel in param saddr on success, else a pointer encoded error code.
12958c2ecf20Sopenharmony_ci */
12968c2ecf20Sopenharmony_ci
12978c2ecf20Sopenharmony_cistruct dst_entry *ip6_dst_lookup_tunnel(struct sk_buff *skb,
12988c2ecf20Sopenharmony_ci					struct net_device *dev,
12998c2ecf20Sopenharmony_ci					struct net *net,
13008c2ecf20Sopenharmony_ci					struct socket *sock,
13018c2ecf20Sopenharmony_ci					struct in6_addr *saddr,
13028c2ecf20Sopenharmony_ci					const struct ip_tunnel_info *info,
13038c2ecf20Sopenharmony_ci					u8 protocol,
13048c2ecf20Sopenharmony_ci					bool use_cache)
13058c2ecf20Sopenharmony_ci{
13068c2ecf20Sopenharmony_ci	struct dst_entry *dst = NULL;
13078c2ecf20Sopenharmony_ci#ifdef CONFIG_DST_CACHE
13088c2ecf20Sopenharmony_ci	struct dst_cache *dst_cache;
13098c2ecf20Sopenharmony_ci#endif
13108c2ecf20Sopenharmony_ci	struct flowi6 fl6;
13118c2ecf20Sopenharmony_ci	__u8 prio;
13128c2ecf20Sopenharmony_ci
13138c2ecf20Sopenharmony_ci#ifdef CONFIG_DST_CACHE
13148c2ecf20Sopenharmony_ci	dst_cache = (struct dst_cache *)&info->dst_cache;
13158c2ecf20Sopenharmony_ci	if (use_cache) {
13168c2ecf20Sopenharmony_ci		dst = dst_cache_get_ip6(dst_cache, saddr);
13178c2ecf20Sopenharmony_ci		if (dst)
13188c2ecf20Sopenharmony_ci			return dst;
13198c2ecf20Sopenharmony_ci	}
13208c2ecf20Sopenharmony_ci#endif
13218c2ecf20Sopenharmony_ci	memset(&fl6, 0, sizeof(fl6));
13228c2ecf20Sopenharmony_ci	fl6.flowi6_mark = skb->mark;
13238c2ecf20Sopenharmony_ci	fl6.flowi6_proto = protocol;
13248c2ecf20Sopenharmony_ci	fl6.daddr = info->key.u.ipv6.dst;
13258c2ecf20Sopenharmony_ci	fl6.saddr = info->key.u.ipv6.src;
13268c2ecf20Sopenharmony_ci	prio = info->key.tos;
13278c2ecf20Sopenharmony_ci	fl6.flowlabel = ip6_make_flowinfo(prio, info->key.label);
13288c2ecf20Sopenharmony_ci
13298c2ecf20Sopenharmony_ci	dst = ipv6_stub->ipv6_dst_lookup_flow(net, sock->sk, &fl6,
13308c2ecf20Sopenharmony_ci					      NULL);
13318c2ecf20Sopenharmony_ci	if (IS_ERR(dst)) {
13328c2ecf20Sopenharmony_ci		netdev_dbg(dev, "no route to %pI6\n", &fl6.daddr);
13338c2ecf20Sopenharmony_ci		return ERR_PTR(-ENETUNREACH);
13348c2ecf20Sopenharmony_ci	}
13358c2ecf20Sopenharmony_ci	if (dst->dev == dev) { /* is this necessary? */
13368c2ecf20Sopenharmony_ci		netdev_dbg(dev, "circular route to %pI6\n", &fl6.daddr);
13378c2ecf20Sopenharmony_ci		dst_release(dst);
13388c2ecf20Sopenharmony_ci		return ERR_PTR(-ELOOP);
13398c2ecf20Sopenharmony_ci	}
13408c2ecf20Sopenharmony_ci#ifdef CONFIG_DST_CACHE
13418c2ecf20Sopenharmony_ci	if (use_cache)
13428c2ecf20Sopenharmony_ci		dst_cache_set_ip6(dst_cache, dst, &fl6.saddr);
13438c2ecf20Sopenharmony_ci#endif
13448c2ecf20Sopenharmony_ci	*saddr = fl6.saddr;
13458c2ecf20Sopenharmony_ci	return dst;
13468c2ecf20Sopenharmony_ci}
13478c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(ip6_dst_lookup_tunnel);
13488c2ecf20Sopenharmony_ci
13498c2ecf20Sopenharmony_cistatic inline struct ipv6_opt_hdr *ip6_opt_dup(struct ipv6_opt_hdr *src,
13508c2ecf20Sopenharmony_ci					       gfp_t gfp)
13518c2ecf20Sopenharmony_ci{
13528c2ecf20Sopenharmony_ci	return src ? kmemdup(src, (src->hdrlen + 1) * 8, gfp) : NULL;
13538c2ecf20Sopenharmony_ci}
13548c2ecf20Sopenharmony_ci
13558c2ecf20Sopenharmony_cistatic inline struct ipv6_rt_hdr *ip6_rthdr_dup(struct ipv6_rt_hdr *src,
13568c2ecf20Sopenharmony_ci						gfp_t gfp)
13578c2ecf20Sopenharmony_ci{
13588c2ecf20Sopenharmony_ci	return src ? kmemdup(src, (src->hdrlen + 1) * 8, gfp) : NULL;
13598c2ecf20Sopenharmony_ci}
13608c2ecf20Sopenharmony_ci
13618c2ecf20Sopenharmony_cistatic void ip6_append_data_mtu(unsigned int *mtu,
13628c2ecf20Sopenharmony_ci				int *maxfraglen,
13638c2ecf20Sopenharmony_ci				unsigned int fragheaderlen,
13648c2ecf20Sopenharmony_ci				struct sk_buff *skb,
13658c2ecf20Sopenharmony_ci				struct rt6_info *rt,
13668c2ecf20Sopenharmony_ci				unsigned int orig_mtu)
13678c2ecf20Sopenharmony_ci{
13688c2ecf20Sopenharmony_ci	if (!(rt->dst.flags & DST_XFRM_TUNNEL)) {
13698c2ecf20Sopenharmony_ci		if (!skb) {
13708c2ecf20Sopenharmony_ci			/* first fragment, reserve header_len */
13718c2ecf20Sopenharmony_ci			*mtu = orig_mtu - rt->dst.header_len;
13728c2ecf20Sopenharmony_ci
13738c2ecf20Sopenharmony_ci		} else {
13748c2ecf20Sopenharmony_ci			/*
13758c2ecf20Sopenharmony_ci			 * this fragment is not first, the headers
13768c2ecf20Sopenharmony_ci			 * space is regarded as data space.
13778c2ecf20Sopenharmony_ci			 */
13788c2ecf20Sopenharmony_ci			*mtu = orig_mtu;
13798c2ecf20Sopenharmony_ci		}
13808c2ecf20Sopenharmony_ci		*maxfraglen = ((*mtu - fragheaderlen) & ~7)
13818c2ecf20Sopenharmony_ci			      + fragheaderlen - sizeof(struct frag_hdr);
13828c2ecf20Sopenharmony_ci	}
13838c2ecf20Sopenharmony_ci}
13848c2ecf20Sopenharmony_ci
13858c2ecf20Sopenharmony_cistatic int ip6_setup_cork(struct sock *sk, struct inet_cork_full *cork,
13868c2ecf20Sopenharmony_ci			  struct inet6_cork *v6_cork, struct ipcm6_cookie *ipc6,
13878c2ecf20Sopenharmony_ci			  struct rt6_info *rt, struct flowi6 *fl6)
13888c2ecf20Sopenharmony_ci{
13898c2ecf20Sopenharmony_ci	struct ipv6_pinfo *np = inet6_sk(sk);
13908c2ecf20Sopenharmony_ci	unsigned int mtu;
13918c2ecf20Sopenharmony_ci	struct ipv6_txoptions *opt = ipc6->opt;
13928c2ecf20Sopenharmony_ci
13938c2ecf20Sopenharmony_ci	/*
13948c2ecf20Sopenharmony_ci	 * setup for corking
13958c2ecf20Sopenharmony_ci	 */
13968c2ecf20Sopenharmony_ci	if (opt) {
13978c2ecf20Sopenharmony_ci		if (WARN_ON(v6_cork->opt))
13988c2ecf20Sopenharmony_ci			return -EINVAL;
13998c2ecf20Sopenharmony_ci
14008c2ecf20Sopenharmony_ci		v6_cork->opt = kzalloc(sizeof(*opt), sk->sk_allocation);
14018c2ecf20Sopenharmony_ci		if (unlikely(!v6_cork->opt))
14028c2ecf20Sopenharmony_ci			return -ENOBUFS;
14038c2ecf20Sopenharmony_ci
14048c2ecf20Sopenharmony_ci		v6_cork->opt->tot_len = sizeof(*opt);
14058c2ecf20Sopenharmony_ci		v6_cork->opt->opt_flen = opt->opt_flen;
14068c2ecf20Sopenharmony_ci		v6_cork->opt->opt_nflen = opt->opt_nflen;
14078c2ecf20Sopenharmony_ci
14088c2ecf20Sopenharmony_ci		v6_cork->opt->dst0opt = ip6_opt_dup(opt->dst0opt,
14098c2ecf20Sopenharmony_ci						    sk->sk_allocation);
14108c2ecf20Sopenharmony_ci		if (opt->dst0opt && !v6_cork->opt->dst0opt)
14118c2ecf20Sopenharmony_ci			return -ENOBUFS;
14128c2ecf20Sopenharmony_ci
14138c2ecf20Sopenharmony_ci		v6_cork->opt->dst1opt = ip6_opt_dup(opt->dst1opt,
14148c2ecf20Sopenharmony_ci						    sk->sk_allocation);
14158c2ecf20Sopenharmony_ci		if (opt->dst1opt && !v6_cork->opt->dst1opt)
14168c2ecf20Sopenharmony_ci			return -ENOBUFS;
14178c2ecf20Sopenharmony_ci
14188c2ecf20Sopenharmony_ci		v6_cork->opt->hopopt = ip6_opt_dup(opt->hopopt,
14198c2ecf20Sopenharmony_ci						   sk->sk_allocation);
14208c2ecf20Sopenharmony_ci		if (opt->hopopt && !v6_cork->opt->hopopt)
14218c2ecf20Sopenharmony_ci			return -ENOBUFS;
14228c2ecf20Sopenharmony_ci
14238c2ecf20Sopenharmony_ci		v6_cork->opt->srcrt = ip6_rthdr_dup(opt->srcrt,
14248c2ecf20Sopenharmony_ci						    sk->sk_allocation);
14258c2ecf20Sopenharmony_ci		if (opt->srcrt && !v6_cork->opt->srcrt)
14268c2ecf20Sopenharmony_ci			return -ENOBUFS;
14278c2ecf20Sopenharmony_ci
14288c2ecf20Sopenharmony_ci		/* need source address above miyazawa*/
14298c2ecf20Sopenharmony_ci	}
14308c2ecf20Sopenharmony_ci	dst_hold(&rt->dst);
14318c2ecf20Sopenharmony_ci	cork->base.dst = &rt->dst;
14328c2ecf20Sopenharmony_ci	cork->fl.u.ip6 = *fl6;
14338c2ecf20Sopenharmony_ci	v6_cork->hop_limit = ipc6->hlimit;
14348c2ecf20Sopenharmony_ci	v6_cork->tclass = ipc6->tclass;
14358c2ecf20Sopenharmony_ci	if (rt->dst.flags & DST_XFRM_TUNNEL)
14368c2ecf20Sopenharmony_ci		mtu = np->pmtudisc >= IPV6_PMTUDISC_PROBE ?
14378c2ecf20Sopenharmony_ci		      READ_ONCE(rt->dst.dev->mtu) : dst_mtu(&rt->dst);
14388c2ecf20Sopenharmony_ci	else
14398c2ecf20Sopenharmony_ci		mtu = np->pmtudisc >= IPV6_PMTUDISC_PROBE ?
14408c2ecf20Sopenharmony_ci			READ_ONCE(rt->dst.dev->mtu) : dst_mtu(xfrm_dst_path(&rt->dst));
14418c2ecf20Sopenharmony_ci	if (np->frag_size < mtu) {
14428c2ecf20Sopenharmony_ci		if (np->frag_size)
14438c2ecf20Sopenharmony_ci			mtu = np->frag_size;
14448c2ecf20Sopenharmony_ci	}
14458c2ecf20Sopenharmony_ci	cork->base.fragsize = mtu;
14468c2ecf20Sopenharmony_ci	cork->base.gso_size = ipc6->gso_size;
14478c2ecf20Sopenharmony_ci	cork->base.tx_flags = 0;
14488c2ecf20Sopenharmony_ci	cork->base.mark = ipc6->sockc.mark;
14498c2ecf20Sopenharmony_ci	sock_tx_timestamp(sk, ipc6->sockc.tsflags, &cork->base.tx_flags);
14508c2ecf20Sopenharmony_ci
14518c2ecf20Sopenharmony_ci	if (dst_allfrag(xfrm_dst_path(&rt->dst)))
14528c2ecf20Sopenharmony_ci		cork->base.flags |= IPCORK_ALLFRAG;
14538c2ecf20Sopenharmony_ci	cork->base.length = 0;
14548c2ecf20Sopenharmony_ci
14558c2ecf20Sopenharmony_ci	cork->base.transmit_time = ipc6->sockc.transmit_time;
14568c2ecf20Sopenharmony_ci
14578c2ecf20Sopenharmony_ci	return 0;
14588c2ecf20Sopenharmony_ci}
14598c2ecf20Sopenharmony_ci
14608c2ecf20Sopenharmony_cistatic int __ip6_append_data(struct sock *sk,
14618c2ecf20Sopenharmony_ci			     struct flowi6 *fl6,
14628c2ecf20Sopenharmony_ci			     struct sk_buff_head *queue,
14638c2ecf20Sopenharmony_ci			     struct inet_cork *cork,
14648c2ecf20Sopenharmony_ci			     struct inet6_cork *v6_cork,
14658c2ecf20Sopenharmony_ci			     struct page_frag *pfrag,
14668c2ecf20Sopenharmony_ci			     int getfrag(void *from, char *to, int offset,
14678c2ecf20Sopenharmony_ci					 int len, int odd, struct sk_buff *skb),
14688c2ecf20Sopenharmony_ci			     void *from, int length, int transhdrlen,
14698c2ecf20Sopenharmony_ci			     unsigned int flags, struct ipcm6_cookie *ipc6)
14708c2ecf20Sopenharmony_ci{
14718c2ecf20Sopenharmony_ci	struct sk_buff *skb, *skb_prev = NULL;
14728c2ecf20Sopenharmony_ci	unsigned int maxfraglen, fragheaderlen, mtu, orig_mtu, pmtu;
14738c2ecf20Sopenharmony_ci	struct ubuf_info *uarg = NULL;
14748c2ecf20Sopenharmony_ci	int exthdrlen = 0;
14758c2ecf20Sopenharmony_ci	int dst_exthdrlen = 0;
14768c2ecf20Sopenharmony_ci	int hh_len;
14778c2ecf20Sopenharmony_ci	int copy;
14788c2ecf20Sopenharmony_ci	int err;
14798c2ecf20Sopenharmony_ci	int offset = 0;
14808c2ecf20Sopenharmony_ci	u32 tskey = 0;
14818c2ecf20Sopenharmony_ci	struct rt6_info *rt = (struct rt6_info *)cork->dst;
14828c2ecf20Sopenharmony_ci	struct ipv6_txoptions *opt = v6_cork->opt;
14838c2ecf20Sopenharmony_ci	int csummode = CHECKSUM_NONE;
14848c2ecf20Sopenharmony_ci	unsigned int maxnonfragsize, headersize;
14858c2ecf20Sopenharmony_ci	unsigned int wmem_alloc_delta = 0;
14868c2ecf20Sopenharmony_ci	bool paged, extra_uref = false;
14878c2ecf20Sopenharmony_ci
14888c2ecf20Sopenharmony_ci	skb = skb_peek_tail(queue);
14898c2ecf20Sopenharmony_ci	if (!skb) {
14908c2ecf20Sopenharmony_ci		exthdrlen = opt ? opt->opt_flen : 0;
14918c2ecf20Sopenharmony_ci		dst_exthdrlen = rt->dst.header_len - rt->rt6i_nfheader_len;
14928c2ecf20Sopenharmony_ci	}
14938c2ecf20Sopenharmony_ci
14948c2ecf20Sopenharmony_ci	paged = !!cork->gso_size;
14958c2ecf20Sopenharmony_ci	mtu = cork->gso_size ? IP6_MAX_MTU : cork->fragsize;
14968c2ecf20Sopenharmony_ci	orig_mtu = mtu;
14978c2ecf20Sopenharmony_ci
14988c2ecf20Sopenharmony_ci	if (cork->tx_flags & SKBTX_ANY_SW_TSTAMP &&
14998c2ecf20Sopenharmony_ci	    sk->sk_tsflags & SOF_TIMESTAMPING_OPT_ID)
15008c2ecf20Sopenharmony_ci		tskey = sk->sk_tskey++;
15018c2ecf20Sopenharmony_ci
15028c2ecf20Sopenharmony_ci	hh_len = LL_RESERVED_SPACE(rt->dst.dev);
15038c2ecf20Sopenharmony_ci
15048c2ecf20Sopenharmony_ci	fragheaderlen = sizeof(struct ipv6hdr) + rt->rt6i_nfheader_len +
15058c2ecf20Sopenharmony_ci			(opt ? opt->opt_nflen : 0);
15068c2ecf20Sopenharmony_ci
15078c2ecf20Sopenharmony_ci	headersize = sizeof(struct ipv6hdr) +
15088c2ecf20Sopenharmony_ci		     (opt ? opt->opt_flen + opt->opt_nflen : 0) +
15098c2ecf20Sopenharmony_ci		     (dst_allfrag(&rt->dst) ?
15108c2ecf20Sopenharmony_ci		      sizeof(struct frag_hdr) : 0) +
15118c2ecf20Sopenharmony_ci		     rt->rt6i_nfheader_len;
15128c2ecf20Sopenharmony_ci
15138c2ecf20Sopenharmony_ci	if (mtu <= fragheaderlen ||
15148c2ecf20Sopenharmony_ci	    ((mtu - fragheaderlen) & ~7) + fragheaderlen <= sizeof(struct frag_hdr))
15158c2ecf20Sopenharmony_ci		goto emsgsize;
15168c2ecf20Sopenharmony_ci
15178c2ecf20Sopenharmony_ci	maxfraglen = ((mtu - fragheaderlen) & ~7) + fragheaderlen -
15188c2ecf20Sopenharmony_ci		     sizeof(struct frag_hdr);
15198c2ecf20Sopenharmony_ci
15208c2ecf20Sopenharmony_ci	/* as per RFC 7112 section 5, the entire IPv6 Header Chain must fit
15218c2ecf20Sopenharmony_ci	 * the first fragment
15228c2ecf20Sopenharmony_ci	 */
15238c2ecf20Sopenharmony_ci	if (headersize + transhdrlen > mtu)
15248c2ecf20Sopenharmony_ci		goto emsgsize;
15258c2ecf20Sopenharmony_ci
15268c2ecf20Sopenharmony_ci	if (cork->length + length > mtu - headersize && ipc6->dontfrag &&
15278c2ecf20Sopenharmony_ci	    (sk->sk_protocol == IPPROTO_UDP ||
15288c2ecf20Sopenharmony_ci	     sk->sk_protocol == IPPROTO_RAW)) {
15298c2ecf20Sopenharmony_ci		ipv6_local_rxpmtu(sk, fl6, mtu - headersize +
15308c2ecf20Sopenharmony_ci				sizeof(struct ipv6hdr));
15318c2ecf20Sopenharmony_ci		goto emsgsize;
15328c2ecf20Sopenharmony_ci	}
15338c2ecf20Sopenharmony_ci
15348c2ecf20Sopenharmony_ci	if (ip6_sk_ignore_df(sk))
15358c2ecf20Sopenharmony_ci		maxnonfragsize = sizeof(struct ipv6hdr) + IPV6_MAXPLEN;
15368c2ecf20Sopenharmony_ci	else
15378c2ecf20Sopenharmony_ci		maxnonfragsize = mtu;
15388c2ecf20Sopenharmony_ci
15398c2ecf20Sopenharmony_ci	if (cork->length + length > maxnonfragsize - headersize) {
15408c2ecf20Sopenharmony_ciemsgsize:
15418c2ecf20Sopenharmony_ci		pmtu = max_t(int, mtu - headersize + sizeof(struct ipv6hdr), 0);
15428c2ecf20Sopenharmony_ci		ipv6_local_error(sk, EMSGSIZE, fl6, pmtu);
15438c2ecf20Sopenharmony_ci		return -EMSGSIZE;
15448c2ecf20Sopenharmony_ci	}
15458c2ecf20Sopenharmony_ci
15468c2ecf20Sopenharmony_ci	/* CHECKSUM_PARTIAL only with no extension headers and when
15478c2ecf20Sopenharmony_ci	 * we are not going to fragment
15488c2ecf20Sopenharmony_ci	 */
15498c2ecf20Sopenharmony_ci	if (transhdrlen && sk->sk_protocol == IPPROTO_UDP &&
15508c2ecf20Sopenharmony_ci	    headersize == sizeof(struct ipv6hdr) &&
15518c2ecf20Sopenharmony_ci	    length <= mtu - headersize &&
15528c2ecf20Sopenharmony_ci	    (!(flags & MSG_MORE) || cork->gso_size) &&
15538c2ecf20Sopenharmony_ci	    rt->dst.dev->features & (NETIF_F_IPV6_CSUM | NETIF_F_HW_CSUM))
15548c2ecf20Sopenharmony_ci		csummode = CHECKSUM_PARTIAL;
15558c2ecf20Sopenharmony_ci
15568c2ecf20Sopenharmony_ci	if (flags & MSG_ZEROCOPY && length && sock_flag(sk, SOCK_ZEROCOPY)) {
15578c2ecf20Sopenharmony_ci		uarg = sock_zerocopy_realloc(sk, length, skb_zcopy(skb));
15588c2ecf20Sopenharmony_ci		if (!uarg)
15598c2ecf20Sopenharmony_ci			return -ENOBUFS;
15608c2ecf20Sopenharmony_ci		extra_uref = !skb_zcopy(skb);	/* only ref on new uarg */
15618c2ecf20Sopenharmony_ci		if (rt->dst.dev->features & NETIF_F_SG &&
15628c2ecf20Sopenharmony_ci		    csummode == CHECKSUM_PARTIAL) {
15638c2ecf20Sopenharmony_ci			paged = true;
15648c2ecf20Sopenharmony_ci		} else {
15658c2ecf20Sopenharmony_ci			uarg->zerocopy = 0;
15668c2ecf20Sopenharmony_ci			skb_zcopy_set(skb, uarg, &extra_uref);
15678c2ecf20Sopenharmony_ci		}
15688c2ecf20Sopenharmony_ci	}
15698c2ecf20Sopenharmony_ci
15708c2ecf20Sopenharmony_ci	/*
15718c2ecf20Sopenharmony_ci	 * Let's try using as much space as possible.
15728c2ecf20Sopenharmony_ci	 * Use MTU if total length of the message fits into the MTU.
15738c2ecf20Sopenharmony_ci	 * Otherwise, we need to reserve fragment header and
15748c2ecf20Sopenharmony_ci	 * fragment alignment (= 8-15 octects, in total).
15758c2ecf20Sopenharmony_ci	 *
15768c2ecf20Sopenharmony_ci	 * Note that we may need to "move" the data from the tail
15778c2ecf20Sopenharmony_ci	 * of the buffer to the new fragment when we split
15788c2ecf20Sopenharmony_ci	 * the message.
15798c2ecf20Sopenharmony_ci	 *
15808c2ecf20Sopenharmony_ci	 * FIXME: It may be fragmented into multiple chunks
15818c2ecf20Sopenharmony_ci	 *        at once if non-fragmentable extension headers
15828c2ecf20Sopenharmony_ci	 *        are too large.
15838c2ecf20Sopenharmony_ci	 * --yoshfuji
15848c2ecf20Sopenharmony_ci	 */
15858c2ecf20Sopenharmony_ci
15868c2ecf20Sopenharmony_ci	cork->length += length;
15878c2ecf20Sopenharmony_ci	if (!skb)
15888c2ecf20Sopenharmony_ci		goto alloc_new_skb;
15898c2ecf20Sopenharmony_ci
15908c2ecf20Sopenharmony_ci	while (length > 0) {
15918c2ecf20Sopenharmony_ci		/* Check if the remaining data fits into current packet. */
15928c2ecf20Sopenharmony_ci		copy = (cork->length <= mtu && !(cork->flags & IPCORK_ALLFRAG) ? mtu : maxfraglen) - skb->len;
15938c2ecf20Sopenharmony_ci		if (copy < length)
15948c2ecf20Sopenharmony_ci			copy = maxfraglen - skb->len;
15958c2ecf20Sopenharmony_ci
15968c2ecf20Sopenharmony_ci		if (copy <= 0) {
15978c2ecf20Sopenharmony_ci			char *data;
15988c2ecf20Sopenharmony_ci			unsigned int datalen;
15998c2ecf20Sopenharmony_ci			unsigned int fraglen;
16008c2ecf20Sopenharmony_ci			unsigned int fraggap;
16018c2ecf20Sopenharmony_ci			unsigned int alloclen, alloc_extra;
16028c2ecf20Sopenharmony_ci			unsigned int pagedlen;
16038c2ecf20Sopenharmony_cialloc_new_skb:
16048c2ecf20Sopenharmony_ci			/* There's no room in the current skb */
16058c2ecf20Sopenharmony_ci			if (skb)
16068c2ecf20Sopenharmony_ci				fraggap = skb->len - maxfraglen;
16078c2ecf20Sopenharmony_ci			else
16088c2ecf20Sopenharmony_ci				fraggap = 0;
16098c2ecf20Sopenharmony_ci			/* update mtu and maxfraglen if necessary */
16108c2ecf20Sopenharmony_ci			if (!skb || !skb_prev)
16118c2ecf20Sopenharmony_ci				ip6_append_data_mtu(&mtu, &maxfraglen,
16128c2ecf20Sopenharmony_ci						    fragheaderlen, skb, rt,
16138c2ecf20Sopenharmony_ci						    orig_mtu);
16148c2ecf20Sopenharmony_ci
16158c2ecf20Sopenharmony_ci			skb_prev = skb;
16168c2ecf20Sopenharmony_ci
16178c2ecf20Sopenharmony_ci			/*
16188c2ecf20Sopenharmony_ci			 * If remaining data exceeds the mtu,
16198c2ecf20Sopenharmony_ci			 * we know we need more fragment(s).
16208c2ecf20Sopenharmony_ci			 */
16218c2ecf20Sopenharmony_ci			datalen = length + fraggap;
16228c2ecf20Sopenharmony_ci
16238c2ecf20Sopenharmony_ci			if (datalen > (cork->length <= mtu && !(cork->flags & IPCORK_ALLFRAG) ? mtu : maxfraglen) - fragheaderlen)
16248c2ecf20Sopenharmony_ci				datalen = maxfraglen - fragheaderlen - rt->dst.trailer_len;
16258c2ecf20Sopenharmony_ci			fraglen = datalen + fragheaderlen;
16268c2ecf20Sopenharmony_ci			pagedlen = 0;
16278c2ecf20Sopenharmony_ci
16288c2ecf20Sopenharmony_ci			alloc_extra = hh_len;
16298c2ecf20Sopenharmony_ci			alloc_extra += dst_exthdrlen;
16308c2ecf20Sopenharmony_ci			alloc_extra += rt->dst.trailer_len;
16318c2ecf20Sopenharmony_ci
16328c2ecf20Sopenharmony_ci			/* We just reserve space for fragment header.
16338c2ecf20Sopenharmony_ci			 * Note: this may be overallocation if the message
16348c2ecf20Sopenharmony_ci			 * (without MSG_MORE) fits into the MTU.
16358c2ecf20Sopenharmony_ci			 */
16368c2ecf20Sopenharmony_ci			alloc_extra += sizeof(struct frag_hdr);
16378c2ecf20Sopenharmony_ci
16388c2ecf20Sopenharmony_ci			if ((flags & MSG_MORE) &&
16398c2ecf20Sopenharmony_ci			    !(rt->dst.dev->features&NETIF_F_SG))
16408c2ecf20Sopenharmony_ci				alloclen = mtu;
16418c2ecf20Sopenharmony_ci			else if (!paged &&
16428c2ecf20Sopenharmony_ci				 (fraglen + alloc_extra < SKB_MAX_ALLOC ||
16438c2ecf20Sopenharmony_ci				  !(rt->dst.dev->features & NETIF_F_SG)))
16448c2ecf20Sopenharmony_ci				alloclen = fraglen;
16458c2ecf20Sopenharmony_ci			else {
16468c2ecf20Sopenharmony_ci				alloclen = min_t(int, fraglen, MAX_HEADER);
16478c2ecf20Sopenharmony_ci				pagedlen = fraglen - alloclen;
16488c2ecf20Sopenharmony_ci			}
16498c2ecf20Sopenharmony_ci			alloclen += alloc_extra;
16508c2ecf20Sopenharmony_ci
16518c2ecf20Sopenharmony_ci			if (datalen != length + fraggap) {
16528c2ecf20Sopenharmony_ci				/*
16538c2ecf20Sopenharmony_ci				 * this is not the last fragment, the trailer
16548c2ecf20Sopenharmony_ci				 * space is regarded as data space.
16558c2ecf20Sopenharmony_ci				 */
16568c2ecf20Sopenharmony_ci				datalen += rt->dst.trailer_len;
16578c2ecf20Sopenharmony_ci			}
16588c2ecf20Sopenharmony_ci
16598c2ecf20Sopenharmony_ci			fraglen = datalen + fragheaderlen;
16608c2ecf20Sopenharmony_ci
16618c2ecf20Sopenharmony_ci			copy = datalen - transhdrlen - fraggap - pagedlen;
16628c2ecf20Sopenharmony_ci			if (copy < 0) {
16638c2ecf20Sopenharmony_ci				err = -EINVAL;
16648c2ecf20Sopenharmony_ci				goto error;
16658c2ecf20Sopenharmony_ci			}
16668c2ecf20Sopenharmony_ci			if (transhdrlen) {
16678c2ecf20Sopenharmony_ci				skb = sock_alloc_send_skb(sk, alloclen,
16688c2ecf20Sopenharmony_ci						(flags & MSG_DONTWAIT), &err);
16698c2ecf20Sopenharmony_ci			} else {
16708c2ecf20Sopenharmony_ci				skb = NULL;
16718c2ecf20Sopenharmony_ci				if (refcount_read(&sk->sk_wmem_alloc) + wmem_alloc_delta <=
16728c2ecf20Sopenharmony_ci				    2 * sk->sk_sndbuf)
16738c2ecf20Sopenharmony_ci					skb = alloc_skb(alloclen,
16748c2ecf20Sopenharmony_ci							sk->sk_allocation);
16758c2ecf20Sopenharmony_ci				if (unlikely(!skb))
16768c2ecf20Sopenharmony_ci					err = -ENOBUFS;
16778c2ecf20Sopenharmony_ci			}
16788c2ecf20Sopenharmony_ci			if (!skb)
16798c2ecf20Sopenharmony_ci				goto error;
16808c2ecf20Sopenharmony_ci			/*
16818c2ecf20Sopenharmony_ci			 *	Fill in the control structures
16828c2ecf20Sopenharmony_ci			 */
16838c2ecf20Sopenharmony_ci			skb->protocol = htons(ETH_P_IPV6);
16848c2ecf20Sopenharmony_ci			skb->ip_summed = csummode;
16858c2ecf20Sopenharmony_ci			skb->csum = 0;
16868c2ecf20Sopenharmony_ci			/* reserve for fragmentation and ipsec header */
16878c2ecf20Sopenharmony_ci			skb_reserve(skb, hh_len + sizeof(struct frag_hdr) +
16888c2ecf20Sopenharmony_ci				    dst_exthdrlen);
16898c2ecf20Sopenharmony_ci
16908c2ecf20Sopenharmony_ci			/*
16918c2ecf20Sopenharmony_ci			 *	Find where to start putting bytes
16928c2ecf20Sopenharmony_ci			 */
16938c2ecf20Sopenharmony_ci			data = skb_put(skb, fraglen - pagedlen);
16948c2ecf20Sopenharmony_ci			skb_set_network_header(skb, exthdrlen);
16958c2ecf20Sopenharmony_ci			data += fragheaderlen;
16968c2ecf20Sopenharmony_ci			skb->transport_header = (skb->network_header +
16978c2ecf20Sopenharmony_ci						 fragheaderlen);
16988c2ecf20Sopenharmony_ci			if (fraggap) {
16998c2ecf20Sopenharmony_ci				skb->csum = skb_copy_and_csum_bits(
17008c2ecf20Sopenharmony_ci					skb_prev, maxfraglen,
17018c2ecf20Sopenharmony_ci					data + transhdrlen, fraggap);
17028c2ecf20Sopenharmony_ci				skb_prev->csum = csum_sub(skb_prev->csum,
17038c2ecf20Sopenharmony_ci							  skb->csum);
17048c2ecf20Sopenharmony_ci				data += fraggap;
17058c2ecf20Sopenharmony_ci				pskb_trim_unique(skb_prev, maxfraglen);
17068c2ecf20Sopenharmony_ci			}
17078c2ecf20Sopenharmony_ci			if (copy > 0 &&
17088c2ecf20Sopenharmony_ci			    getfrag(from, data + transhdrlen, offset,
17098c2ecf20Sopenharmony_ci				    copy, fraggap, skb) < 0) {
17108c2ecf20Sopenharmony_ci				err = -EFAULT;
17118c2ecf20Sopenharmony_ci				kfree_skb(skb);
17128c2ecf20Sopenharmony_ci				goto error;
17138c2ecf20Sopenharmony_ci			}
17148c2ecf20Sopenharmony_ci
17158c2ecf20Sopenharmony_ci			offset += copy;
17168c2ecf20Sopenharmony_ci			length -= copy + transhdrlen;
17178c2ecf20Sopenharmony_ci			transhdrlen = 0;
17188c2ecf20Sopenharmony_ci			exthdrlen = 0;
17198c2ecf20Sopenharmony_ci			dst_exthdrlen = 0;
17208c2ecf20Sopenharmony_ci
17218c2ecf20Sopenharmony_ci			/* Only the initial fragment is time stamped */
17228c2ecf20Sopenharmony_ci			skb_shinfo(skb)->tx_flags = cork->tx_flags;
17238c2ecf20Sopenharmony_ci			cork->tx_flags = 0;
17248c2ecf20Sopenharmony_ci			skb_shinfo(skb)->tskey = tskey;
17258c2ecf20Sopenharmony_ci			tskey = 0;
17268c2ecf20Sopenharmony_ci			skb_zcopy_set(skb, uarg, &extra_uref);
17278c2ecf20Sopenharmony_ci
17288c2ecf20Sopenharmony_ci			if ((flags & MSG_CONFIRM) && !skb_prev)
17298c2ecf20Sopenharmony_ci				skb_set_dst_pending_confirm(skb, 1);
17308c2ecf20Sopenharmony_ci
17318c2ecf20Sopenharmony_ci			/*
17328c2ecf20Sopenharmony_ci			 * Put the packet on the pending queue
17338c2ecf20Sopenharmony_ci			 */
17348c2ecf20Sopenharmony_ci			if (!skb->destructor) {
17358c2ecf20Sopenharmony_ci				skb->destructor = sock_wfree;
17368c2ecf20Sopenharmony_ci				skb->sk = sk;
17378c2ecf20Sopenharmony_ci				wmem_alloc_delta += skb->truesize;
17388c2ecf20Sopenharmony_ci			}
17398c2ecf20Sopenharmony_ci			__skb_queue_tail(queue, skb);
17408c2ecf20Sopenharmony_ci			continue;
17418c2ecf20Sopenharmony_ci		}
17428c2ecf20Sopenharmony_ci
17438c2ecf20Sopenharmony_ci		if (copy > length)
17448c2ecf20Sopenharmony_ci			copy = length;
17458c2ecf20Sopenharmony_ci
17468c2ecf20Sopenharmony_ci		if (!(rt->dst.dev->features&NETIF_F_SG) &&
17478c2ecf20Sopenharmony_ci		    skb_tailroom(skb) >= copy) {
17488c2ecf20Sopenharmony_ci			unsigned int off;
17498c2ecf20Sopenharmony_ci
17508c2ecf20Sopenharmony_ci			off = skb->len;
17518c2ecf20Sopenharmony_ci			if (getfrag(from, skb_put(skb, copy),
17528c2ecf20Sopenharmony_ci						offset, copy, off, skb) < 0) {
17538c2ecf20Sopenharmony_ci				__skb_trim(skb, off);
17548c2ecf20Sopenharmony_ci				err = -EFAULT;
17558c2ecf20Sopenharmony_ci				goto error;
17568c2ecf20Sopenharmony_ci			}
17578c2ecf20Sopenharmony_ci		} else if (!uarg || !uarg->zerocopy) {
17588c2ecf20Sopenharmony_ci			int i = skb_shinfo(skb)->nr_frags;
17598c2ecf20Sopenharmony_ci
17608c2ecf20Sopenharmony_ci			err = -ENOMEM;
17618c2ecf20Sopenharmony_ci			if (!sk_page_frag_refill(sk, pfrag))
17628c2ecf20Sopenharmony_ci				goto error;
17638c2ecf20Sopenharmony_ci
17648c2ecf20Sopenharmony_ci			if (!skb_can_coalesce(skb, i, pfrag->page,
17658c2ecf20Sopenharmony_ci					      pfrag->offset)) {
17668c2ecf20Sopenharmony_ci				err = -EMSGSIZE;
17678c2ecf20Sopenharmony_ci				if (i == MAX_SKB_FRAGS)
17688c2ecf20Sopenharmony_ci					goto error;
17698c2ecf20Sopenharmony_ci
17708c2ecf20Sopenharmony_ci				__skb_fill_page_desc(skb, i, pfrag->page,
17718c2ecf20Sopenharmony_ci						     pfrag->offset, 0);
17728c2ecf20Sopenharmony_ci				skb_shinfo(skb)->nr_frags = ++i;
17738c2ecf20Sopenharmony_ci				get_page(pfrag->page);
17748c2ecf20Sopenharmony_ci			}
17758c2ecf20Sopenharmony_ci			copy = min_t(int, copy, pfrag->size - pfrag->offset);
17768c2ecf20Sopenharmony_ci			if (getfrag(from,
17778c2ecf20Sopenharmony_ci				    page_address(pfrag->page) + pfrag->offset,
17788c2ecf20Sopenharmony_ci				    offset, copy, skb->len, skb) < 0)
17798c2ecf20Sopenharmony_ci				goto error_efault;
17808c2ecf20Sopenharmony_ci
17818c2ecf20Sopenharmony_ci			pfrag->offset += copy;
17828c2ecf20Sopenharmony_ci			skb_frag_size_add(&skb_shinfo(skb)->frags[i - 1], copy);
17838c2ecf20Sopenharmony_ci			skb->len += copy;
17848c2ecf20Sopenharmony_ci			skb->data_len += copy;
17858c2ecf20Sopenharmony_ci			skb->truesize += copy;
17868c2ecf20Sopenharmony_ci			wmem_alloc_delta += copy;
17878c2ecf20Sopenharmony_ci		} else {
17888c2ecf20Sopenharmony_ci			err = skb_zerocopy_iter_dgram(skb, from, copy);
17898c2ecf20Sopenharmony_ci			if (err < 0)
17908c2ecf20Sopenharmony_ci				goto error;
17918c2ecf20Sopenharmony_ci		}
17928c2ecf20Sopenharmony_ci		offset += copy;
17938c2ecf20Sopenharmony_ci		length -= copy;
17948c2ecf20Sopenharmony_ci	}
17958c2ecf20Sopenharmony_ci
17968c2ecf20Sopenharmony_ci	if (wmem_alloc_delta)
17978c2ecf20Sopenharmony_ci		refcount_add(wmem_alloc_delta, &sk->sk_wmem_alloc);
17988c2ecf20Sopenharmony_ci	return 0;
17998c2ecf20Sopenharmony_ci
18008c2ecf20Sopenharmony_cierror_efault:
18018c2ecf20Sopenharmony_ci	err = -EFAULT;
18028c2ecf20Sopenharmony_cierror:
18038c2ecf20Sopenharmony_ci	if (uarg)
18048c2ecf20Sopenharmony_ci		sock_zerocopy_put_abort(uarg, extra_uref);
18058c2ecf20Sopenharmony_ci	cork->length -= length;
18068c2ecf20Sopenharmony_ci	IP6_INC_STATS(sock_net(sk), rt->rt6i_idev, IPSTATS_MIB_OUTDISCARDS);
18078c2ecf20Sopenharmony_ci	refcount_add(wmem_alloc_delta, &sk->sk_wmem_alloc);
18088c2ecf20Sopenharmony_ci	return err;
18098c2ecf20Sopenharmony_ci}
18108c2ecf20Sopenharmony_ci
18118c2ecf20Sopenharmony_ciint ip6_append_data(struct sock *sk,
18128c2ecf20Sopenharmony_ci		    int getfrag(void *from, char *to, int offset, int len,
18138c2ecf20Sopenharmony_ci				int odd, struct sk_buff *skb),
18148c2ecf20Sopenharmony_ci		    void *from, int length, int transhdrlen,
18158c2ecf20Sopenharmony_ci		    struct ipcm6_cookie *ipc6, struct flowi6 *fl6,
18168c2ecf20Sopenharmony_ci		    struct rt6_info *rt, unsigned int flags)
18178c2ecf20Sopenharmony_ci{
18188c2ecf20Sopenharmony_ci	struct inet_sock *inet = inet_sk(sk);
18198c2ecf20Sopenharmony_ci	struct ipv6_pinfo *np = inet6_sk(sk);
18208c2ecf20Sopenharmony_ci	int exthdrlen;
18218c2ecf20Sopenharmony_ci	int err;
18228c2ecf20Sopenharmony_ci
18238c2ecf20Sopenharmony_ci	if (flags&MSG_PROBE)
18248c2ecf20Sopenharmony_ci		return 0;
18258c2ecf20Sopenharmony_ci	if (skb_queue_empty(&sk->sk_write_queue)) {
18268c2ecf20Sopenharmony_ci		/*
18278c2ecf20Sopenharmony_ci		 * setup for corking
18288c2ecf20Sopenharmony_ci		 */
18298c2ecf20Sopenharmony_ci		err = ip6_setup_cork(sk, &inet->cork, &np->cork,
18308c2ecf20Sopenharmony_ci				     ipc6, rt, fl6);
18318c2ecf20Sopenharmony_ci		if (err)
18328c2ecf20Sopenharmony_ci			return err;
18338c2ecf20Sopenharmony_ci
18348c2ecf20Sopenharmony_ci		exthdrlen = (ipc6->opt ? ipc6->opt->opt_flen : 0);
18358c2ecf20Sopenharmony_ci		length += exthdrlen;
18368c2ecf20Sopenharmony_ci		transhdrlen += exthdrlen;
18378c2ecf20Sopenharmony_ci	} else {
18388c2ecf20Sopenharmony_ci		fl6 = &inet->cork.fl.u.ip6;
18398c2ecf20Sopenharmony_ci		transhdrlen = 0;
18408c2ecf20Sopenharmony_ci	}
18418c2ecf20Sopenharmony_ci
18428c2ecf20Sopenharmony_ci	return __ip6_append_data(sk, fl6, &sk->sk_write_queue, &inet->cork.base,
18438c2ecf20Sopenharmony_ci				 &np->cork, sk_page_frag(sk), getfrag,
18448c2ecf20Sopenharmony_ci				 from, length, transhdrlen, flags, ipc6);
18458c2ecf20Sopenharmony_ci}
18468c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(ip6_append_data);
18478c2ecf20Sopenharmony_ci
18488c2ecf20Sopenharmony_cistatic void ip6_cork_release(struct inet_cork_full *cork,
18498c2ecf20Sopenharmony_ci			     struct inet6_cork *v6_cork)
18508c2ecf20Sopenharmony_ci{
18518c2ecf20Sopenharmony_ci	if (v6_cork->opt) {
18528c2ecf20Sopenharmony_ci		kfree(v6_cork->opt->dst0opt);
18538c2ecf20Sopenharmony_ci		kfree(v6_cork->opt->dst1opt);
18548c2ecf20Sopenharmony_ci		kfree(v6_cork->opt->hopopt);
18558c2ecf20Sopenharmony_ci		kfree(v6_cork->opt->srcrt);
18568c2ecf20Sopenharmony_ci		kfree(v6_cork->opt);
18578c2ecf20Sopenharmony_ci		v6_cork->opt = NULL;
18588c2ecf20Sopenharmony_ci	}
18598c2ecf20Sopenharmony_ci
18608c2ecf20Sopenharmony_ci	if (cork->base.dst) {
18618c2ecf20Sopenharmony_ci		dst_release(cork->base.dst);
18628c2ecf20Sopenharmony_ci		cork->base.dst = NULL;
18638c2ecf20Sopenharmony_ci		cork->base.flags &= ~IPCORK_ALLFRAG;
18648c2ecf20Sopenharmony_ci	}
18658c2ecf20Sopenharmony_ci	memset(&cork->fl, 0, sizeof(cork->fl));
18668c2ecf20Sopenharmony_ci}
18678c2ecf20Sopenharmony_ci
18688c2ecf20Sopenharmony_cistruct sk_buff *__ip6_make_skb(struct sock *sk,
18698c2ecf20Sopenharmony_ci			       struct sk_buff_head *queue,
18708c2ecf20Sopenharmony_ci			       struct inet_cork_full *cork,
18718c2ecf20Sopenharmony_ci			       struct inet6_cork *v6_cork)
18728c2ecf20Sopenharmony_ci{
18738c2ecf20Sopenharmony_ci	struct sk_buff *skb, *tmp_skb;
18748c2ecf20Sopenharmony_ci	struct sk_buff **tail_skb;
18758c2ecf20Sopenharmony_ci	struct in6_addr final_dst_buf, *final_dst = &final_dst_buf;
18768c2ecf20Sopenharmony_ci	struct ipv6_pinfo *np = inet6_sk(sk);
18778c2ecf20Sopenharmony_ci	struct net *net = sock_net(sk);
18788c2ecf20Sopenharmony_ci	struct ipv6hdr *hdr;
18798c2ecf20Sopenharmony_ci	struct ipv6_txoptions *opt = v6_cork->opt;
18808c2ecf20Sopenharmony_ci	struct rt6_info *rt = (struct rt6_info *)cork->base.dst;
18818c2ecf20Sopenharmony_ci	struct flowi6 *fl6 = &cork->fl.u.ip6;
18828c2ecf20Sopenharmony_ci	unsigned char proto = fl6->flowi6_proto;
18838c2ecf20Sopenharmony_ci
18848c2ecf20Sopenharmony_ci	skb = __skb_dequeue(queue);
18858c2ecf20Sopenharmony_ci	if (!skb)
18868c2ecf20Sopenharmony_ci		goto out;
18878c2ecf20Sopenharmony_ci	tail_skb = &(skb_shinfo(skb)->frag_list);
18888c2ecf20Sopenharmony_ci
18898c2ecf20Sopenharmony_ci	/* move skb->data to ip header from ext header */
18908c2ecf20Sopenharmony_ci	if (skb->data < skb_network_header(skb))
18918c2ecf20Sopenharmony_ci		__skb_pull(skb, skb_network_offset(skb));
18928c2ecf20Sopenharmony_ci	while ((tmp_skb = __skb_dequeue(queue)) != NULL) {
18938c2ecf20Sopenharmony_ci		__skb_pull(tmp_skb, skb_network_header_len(skb));
18948c2ecf20Sopenharmony_ci		*tail_skb = tmp_skb;
18958c2ecf20Sopenharmony_ci		tail_skb = &(tmp_skb->next);
18968c2ecf20Sopenharmony_ci		skb->len += tmp_skb->len;
18978c2ecf20Sopenharmony_ci		skb->data_len += tmp_skb->len;
18988c2ecf20Sopenharmony_ci		skb->truesize += tmp_skb->truesize;
18998c2ecf20Sopenharmony_ci		tmp_skb->destructor = NULL;
19008c2ecf20Sopenharmony_ci		tmp_skb->sk = NULL;
19018c2ecf20Sopenharmony_ci	}
19028c2ecf20Sopenharmony_ci
19038c2ecf20Sopenharmony_ci	/* Allow local fragmentation. */
19048c2ecf20Sopenharmony_ci	skb->ignore_df = ip6_sk_ignore_df(sk);
19058c2ecf20Sopenharmony_ci
19068c2ecf20Sopenharmony_ci	*final_dst = fl6->daddr;
19078c2ecf20Sopenharmony_ci	__skb_pull(skb, skb_network_header_len(skb));
19088c2ecf20Sopenharmony_ci	if (opt && opt->opt_flen)
19098c2ecf20Sopenharmony_ci		ipv6_push_frag_opts(skb, opt, &proto);
19108c2ecf20Sopenharmony_ci	if (opt && opt->opt_nflen)
19118c2ecf20Sopenharmony_ci		ipv6_push_nfrag_opts(skb, opt, &proto, &final_dst, &fl6->saddr);
19128c2ecf20Sopenharmony_ci
19138c2ecf20Sopenharmony_ci	skb_push(skb, sizeof(struct ipv6hdr));
19148c2ecf20Sopenharmony_ci	skb_reset_network_header(skb);
19158c2ecf20Sopenharmony_ci	hdr = ipv6_hdr(skb);
19168c2ecf20Sopenharmony_ci
19178c2ecf20Sopenharmony_ci	ip6_flow_hdr(hdr, v6_cork->tclass,
19188c2ecf20Sopenharmony_ci		     ip6_make_flowlabel(net, skb, fl6->flowlabel,
19198c2ecf20Sopenharmony_ci					ip6_autoflowlabel(net, np), fl6));
19208c2ecf20Sopenharmony_ci	hdr->hop_limit = v6_cork->hop_limit;
19218c2ecf20Sopenharmony_ci	hdr->nexthdr = proto;
19228c2ecf20Sopenharmony_ci	hdr->saddr = fl6->saddr;
19238c2ecf20Sopenharmony_ci	hdr->daddr = *final_dst;
19248c2ecf20Sopenharmony_ci
19258c2ecf20Sopenharmony_ci	skb->priority = sk->sk_priority;
19268c2ecf20Sopenharmony_ci	skb->mark = cork->base.mark;
19278c2ecf20Sopenharmony_ci
19288c2ecf20Sopenharmony_ci	skb->tstamp = cork->base.transmit_time;
19298c2ecf20Sopenharmony_ci
19308c2ecf20Sopenharmony_ci	skb_dst_set(skb, dst_clone(&rt->dst));
19318c2ecf20Sopenharmony_ci	IP6_UPD_PO_STATS(net, rt->rt6i_idev, IPSTATS_MIB_OUT, skb->len);
19328c2ecf20Sopenharmony_ci	if (proto == IPPROTO_ICMPV6) {
19338c2ecf20Sopenharmony_ci		struct inet6_dev *idev = ip6_dst_idev(skb_dst(skb));
19348c2ecf20Sopenharmony_ci		u8 icmp6_type;
19358c2ecf20Sopenharmony_ci
19368c2ecf20Sopenharmony_ci		if (sk->sk_socket->type == SOCK_RAW &&
19378c2ecf20Sopenharmony_ci			!(fl6->flowi6_flags & FLOWI_FLAG_KNOWN_NH))
19388c2ecf20Sopenharmony_ci			icmp6_type = fl6->fl6_icmp_type;
19398c2ecf20Sopenharmony_ci		else
19408c2ecf20Sopenharmony_ci			icmp6_type = icmp6_hdr(skb)->icmp6_type;
19418c2ecf20Sopenharmony_ci		ICMP6MSGOUT_INC_STATS(net, idev, icmp6_type);
19428c2ecf20Sopenharmony_ci		ICMP6_INC_STATS(net, idev, ICMP6_MIB_OUTMSGS);
19438c2ecf20Sopenharmony_ci	}
19448c2ecf20Sopenharmony_ci
19458c2ecf20Sopenharmony_ci	ip6_cork_release(cork, v6_cork);
19468c2ecf20Sopenharmony_ciout:
19478c2ecf20Sopenharmony_ci	return skb;
19488c2ecf20Sopenharmony_ci}
19498c2ecf20Sopenharmony_ci
19508c2ecf20Sopenharmony_ciint ip6_send_skb(struct sk_buff *skb)
19518c2ecf20Sopenharmony_ci{
19528c2ecf20Sopenharmony_ci	struct net *net = sock_net(skb->sk);
19538c2ecf20Sopenharmony_ci	struct rt6_info *rt = (struct rt6_info *)skb_dst(skb);
19548c2ecf20Sopenharmony_ci	int err;
19558c2ecf20Sopenharmony_ci
19568c2ecf20Sopenharmony_ci	rcu_read_lock();
19578c2ecf20Sopenharmony_ci	err = ip6_local_out(net, skb->sk, skb);
19588c2ecf20Sopenharmony_ci	if (err) {
19598c2ecf20Sopenharmony_ci		if (err > 0)
19608c2ecf20Sopenharmony_ci			err = net_xmit_errno(err);
19618c2ecf20Sopenharmony_ci		if (err)
19628c2ecf20Sopenharmony_ci			IP6_INC_STATS(net, rt->rt6i_idev,
19638c2ecf20Sopenharmony_ci				      IPSTATS_MIB_OUTDISCARDS);
19648c2ecf20Sopenharmony_ci	}
19658c2ecf20Sopenharmony_ci
19668c2ecf20Sopenharmony_ci	rcu_read_unlock();
19678c2ecf20Sopenharmony_ci	return err;
19688c2ecf20Sopenharmony_ci}
19698c2ecf20Sopenharmony_ci
19708c2ecf20Sopenharmony_ciint ip6_push_pending_frames(struct sock *sk)
19718c2ecf20Sopenharmony_ci{
19728c2ecf20Sopenharmony_ci	struct sk_buff *skb;
19738c2ecf20Sopenharmony_ci
19748c2ecf20Sopenharmony_ci	skb = ip6_finish_skb(sk);
19758c2ecf20Sopenharmony_ci	if (!skb)
19768c2ecf20Sopenharmony_ci		return 0;
19778c2ecf20Sopenharmony_ci
19788c2ecf20Sopenharmony_ci	return ip6_send_skb(skb);
19798c2ecf20Sopenharmony_ci}
19808c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(ip6_push_pending_frames);
19818c2ecf20Sopenharmony_ci
19828c2ecf20Sopenharmony_cistatic void __ip6_flush_pending_frames(struct sock *sk,
19838c2ecf20Sopenharmony_ci				       struct sk_buff_head *queue,
19848c2ecf20Sopenharmony_ci				       struct inet_cork_full *cork,
19858c2ecf20Sopenharmony_ci				       struct inet6_cork *v6_cork)
19868c2ecf20Sopenharmony_ci{
19878c2ecf20Sopenharmony_ci	struct sk_buff *skb;
19888c2ecf20Sopenharmony_ci
19898c2ecf20Sopenharmony_ci	while ((skb = __skb_dequeue_tail(queue)) != NULL) {
19908c2ecf20Sopenharmony_ci		if (skb_dst(skb))
19918c2ecf20Sopenharmony_ci			IP6_INC_STATS(sock_net(sk), ip6_dst_idev(skb_dst(skb)),
19928c2ecf20Sopenharmony_ci				      IPSTATS_MIB_OUTDISCARDS);
19938c2ecf20Sopenharmony_ci		kfree_skb(skb);
19948c2ecf20Sopenharmony_ci	}
19958c2ecf20Sopenharmony_ci
19968c2ecf20Sopenharmony_ci	ip6_cork_release(cork, v6_cork);
19978c2ecf20Sopenharmony_ci}
19988c2ecf20Sopenharmony_ci
19998c2ecf20Sopenharmony_civoid ip6_flush_pending_frames(struct sock *sk)
20008c2ecf20Sopenharmony_ci{
20018c2ecf20Sopenharmony_ci	__ip6_flush_pending_frames(sk, &sk->sk_write_queue,
20028c2ecf20Sopenharmony_ci				   &inet_sk(sk)->cork, &inet6_sk(sk)->cork);
20038c2ecf20Sopenharmony_ci}
20048c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(ip6_flush_pending_frames);
20058c2ecf20Sopenharmony_ci
20068c2ecf20Sopenharmony_cistruct sk_buff *ip6_make_skb(struct sock *sk,
20078c2ecf20Sopenharmony_ci			     int getfrag(void *from, char *to, int offset,
20088c2ecf20Sopenharmony_ci					 int len, int odd, struct sk_buff *skb),
20098c2ecf20Sopenharmony_ci			     void *from, int length, int transhdrlen,
20108c2ecf20Sopenharmony_ci			     struct ipcm6_cookie *ipc6, struct flowi6 *fl6,
20118c2ecf20Sopenharmony_ci			     struct rt6_info *rt, unsigned int flags,
20128c2ecf20Sopenharmony_ci			     struct inet_cork_full *cork)
20138c2ecf20Sopenharmony_ci{
20148c2ecf20Sopenharmony_ci	struct inet6_cork v6_cork;
20158c2ecf20Sopenharmony_ci	struct sk_buff_head queue;
20168c2ecf20Sopenharmony_ci	int exthdrlen = (ipc6->opt ? ipc6->opt->opt_flen : 0);
20178c2ecf20Sopenharmony_ci	int err;
20188c2ecf20Sopenharmony_ci
20198c2ecf20Sopenharmony_ci	if (flags & MSG_PROBE)
20208c2ecf20Sopenharmony_ci		return NULL;
20218c2ecf20Sopenharmony_ci
20228c2ecf20Sopenharmony_ci	__skb_queue_head_init(&queue);
20238c2ecf20Sopenharmony_ci
20248c2ecf20Sopenharmony_ci	cork->base.flags = 0;
20258c2ecf20Sopenharmony_ci	cork->base.addr = 0;
20268c2ecf20Sopenharmony_ci	cork->base.opt = NULL;
20278c2ecf20Sopenharmony_ci	cork->base.dst = NULL;
20288c2ecf20Sopenharmony_ci	v6_cork.opt = NULL;
20298c2ecf20Sopenharmony_ci	err = ip6_setup_cork(sk, cork, &v6_cork, ipc6, rt, fl6);
20308c2ecf20Sopenharmony_ci	if (err) {
20318c2ecf20Sopenharmony_ci		ip6_cork_release(cork, &v6_cork);
20328c2ecf20Sopenharmony_ci		return ERR_PTR(err);
20338c2ecf20Sopenharmony_ci	}
20348c2ecf20Sopenharmony_ci	if (ipc6->dontfrag < 0)
20358c2ecf20Sopenharmony_ci		ipc6->dontfrag = inet6_sk(sk)->dontfrag;
20368c2ecf20Sopenharmony_ci
20378c2ecf20Sopenharmony_ci	err = __ip6_append_data(sk, fl6, &queue, &cork->base, &v6_cork,
20388c2ecf20Sopenharmony_ci				&current->task_frag, getfrag, from,
20398c2ecf20Sopenharmony_ci				length + exthdrlen, transhdrlen + exthdrlen,
20408c2ecf20Sopenharmony_ci				flags, ipc6);
20418c2ecf20Sopenharmony_ci	if (err) {
20428c2ecf20Sopenharmony_ci		__ip6_flush_pending_frames(sk, &queue, cork, &v6_cork);
20438c2ecf20Sopenharmony_ci		return ERR_PTR(err);
20448c2ecf20Sopenharmony_ci	}
20458c2ecf20Sopenharmony_ci
20468c2ecf20Sopenharmony_ci	return __ip6_make_skb(sk, &queue, cork, &v6_cork);
20478c2ecf20Sopenharmony_ci}
2048