xref: /OK3568_Linux_fs/kernel/net/ipv6/output_core.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * IPv6 library code, needed by static components when full IPv6 support is
4*4882a593Smuzhiyun  * not configured or static.  These functions are needed by GSO/GRO implementation.
5*4882a593Smuzhiyun  */
6*4882a593Smuzhiyun #include <linux/export.h>
7*4882a593Smuzhiyun #include <net/ip.h>
8*4882a593Smuzhiyun #include <net/ipv6.h>
9*4882a593Smuzhiyun #include <net/ip6_fib.h>
10*4882a593Smuzhiyun #include <net/addrconf.h>
11*4882a593Smuzhiyun #include <net/secure_seq.h>
12*4882a593Smuzhiyun #include <linux/netfilter.h>
13*4882a593Smuzhiyun 
__ipv6_select_ident(struct net * net,const struct in6_addr * dst,const struct in6_addr * src)14*4882a593Smuzhiyun static u32 __ipv6_select_ident(struct net *net,
15*4882a593Smuzhiyun 			       const struct in6_addr *dst,
16*4882a593Smuzhiyun 			       const struct in6_addr *src)
17*4882a593Smuzhiyun {
18*4882a593Smuzhiyun 	u32 id;
19*4882a593Smuzhiyun 
20*4882a593Smuzhiyun 	do {
21*4882a593Smuzhiyun 		id = prandom_u32();
22*4882a593Smuzhiyun 	} while (!id);
23*4882a593Smuzhiyun 
24*4882a593Smuzhiyun 	return id;
25*4882a593Smuzhiyun }
26*4882a593Smuzhiyun 
27*4882a593Smuzhiyun /* This function exists only for tap drivers that must support broken
28*4882a593Smuzhiyun  * clients requesting UFO without specifying an IPv6 fragment ID.
29*4882a593Smuzhiyun  *
30*4882a593Smuzhiyun  * This is similar to ipv6_select_ident() but we use an independent hash
31*4882a593Smuzhiyun  * seed to limit information leakage.
32*4882a593Smuzhiyun  *
33*4882a593Smuzhiyun  * The network header must be set before calling this.
34*4882a593Smuzhiyun  */
ipv6_proxy_select_ident(struct net * net,struct sk_buff * skb)35*4882a593Smuzhiyun __be32 ipv6_proxy_select_ident(struct net *net, struct sk_buff *skb)
36*4882a593Smuzhiyun {
37*4882a593Smuzhiyun 	struct in6_addr buf[2];
38*4882a593Smuzhiyun 	struct in6_addr *addrs;
39*4882a593Smuzhiyun 	u32 id;
40*4882a593Smuzhiyun 
41*4882a593Smuzhiyun 	addrs = skb_header_pointer(skb,
42*4882a593Smuzhiyun 				   skb_network_offset(skb) +
43*4882a593Smuzhiyun 				   offsetof(struct ipv6hdr, saddr),
44*4882a593Smuzhiyun 				   sizeof(buf), buf);
45*4882a593Smuzhiyun 	if (!addrs)
46*4882a593Smuzhiyun 		return 0;
47*4882a593Smuzhiyun 
48*4882a593Smuzhiyun 	id = __ipv6_select_ident(net, &addrs[1], &addrs[0]);
49*4882a593Smuzhiyun 	return htonl(id);
50*4882a593Smuzhiyun }
51*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(ipv6_proxy_select_ident);
52*4882a593Smuzhiyun 
ipv6_select_ident(struct net * net,const struct in6_addr * daddr,const struct in6_addr * saddr)53*4882a593Smuzhiyun __be32 ipv6_select_ident(struct net *net,
54*4882a593Smuzhiyun 			 const struct in6_addr *daddr,
55*4882a593Smuzhiyun 			 const struct in6_addr *saddr)
56*4882a593Smuzhiyun {
57*4882a593Smuzhiyun 	u32 id;
58*4882a593Smuzhiyun 
59*4882a593Smuzhiyun 	id = __ipv6_select_ident(net, daddr, saddr);
60*4882a593Smuzhiyun 	return htonl(id);
61*4882a593Smuzhiyun }
62*4882a593Smuzhiyun EXPORT_SYMBOL(ipv6_select_ident);
63*4882a593Smuzhiyun 
ip6_find_1stfragopt(struct sk_buff * skb,u8 ** nexthdr)64*4882a593Smuzhiyun int ip6_find_1stfragopt(struct sk_buff *skb, u8 **nexthdr)
65*4882a593Smuzhiyun {
66*4882a593Smuzhiyun 	unsigned int offset = sizeof(struct ipv6hdr);
67*4882a593Smuzhiyun 	unsigned int packet_len = skb_tail_pointer(skb) -
68*4882a593Smuzhiyun 		skb_network_header(skb);
69*4882a593Smuzhiyun 	int found_rhdr = 0;
70*4882a593Smuzhiyun 	*nexthdr = &ipv6_hdr(skb)->nexthdr;
71*4882a593Smuzhiyun 
72*4882a593Smuzhiyun 	while (offset <= packet_len) {
73*4882a593Smuzhiyun 		struct ipv6_opt_hdr *exthdr;
74*4882a593Smuzhiyun 
75*4882a593Smuzhiyun 		switch (**nexthdr) {
76*4882a593Smuzhiyun 
77*4882a593Smuzhiyun 		case NEXTHDR_HOP:
78*4882a593Smuzhiyun 			break;
79*4882a593Smuzhiyun 		case NEXTHDR_ROUTING:
80*4882a593Smuzhiyun 			found_rhdr = 1;
81*4882a593Smuzhiyun 			break;
82*4882a593Smuzhiyun 		case NEXTHDR_DEST:
83*4882a593Smuzhiyun #if IS_ENABLED(CONFIG_IPV6_MIP6)
84*4882a593Smuzhiyun 			if (ipv6_find_tlv(skb, offset, IPV6_TLV_HAO) >= 0)
85*4882a593Smuzhiyun 				break;
86*4882a593Smuzhiyun #endif
87*4882a593Smuzhiyun 			if (found_rhdr)
88*4882a593Smuzhiyun 				return offset;
89*4882a593Smuzhiyun 			break;
90*4882a593Smuzhiyun 		default:
91*4882a593Smuzhiyun 			return offset;
92*4882a593Smuzhiyun 		}
93*4882a593Smuzhiyun 
94*4882a593Smuzhiyun 		if (offset + sizeof(struct ipv6_opt_hdr) > packet_len)
95*4882a593Smuzhiyun 			return -EINVAL;
96*4882a593Smuzhiyun 
97*4882a593Smuzhiyun 		exthdr = (struct ipv6_opt_hdr *)(skb_network_header(skb) +
98*4882a593Smuzhiyun 						 offset);
99*4882a593Smuzhiyun 		offset += ipv6_optlen(exthdr);
100*4882a593Smuzhiyun 		if (offset > IPV6_MAXPLEN)
101*4882a593Smuzhiyun 			return -EINVAL;
102*4882a593Smuzhiyun 		*nexthdr = &exthdr->nexthdr;
103*4882a593Smuzhiyun 	}
104*4882a593Smuzhiyun 
105*4882a593Smuzhiyun 	return -EINVAL;
106*4882a593Smuzhiyun }
107*4882a593Smuzhiyun EXPORT_SYMBOL(ip6_find_1stfragopt);
108*4882a593Smuzhiyun 
109*4882a593Smuzhiyun #if IS_ENABLED(CONFIG_IPV6)
ip6_dst_hoplimit(struct dst_entry * dst)110*4882a593Smuzhiyun int ip6_dst_hoplimit(struct dst_entry *dst)
111*4882a593Smuzhiyun {
112*4882a593Smuzhiyun 	int hoplimit = dst_metric_raw(dst, RTAX_HOPLIMIT);
113*4882a593Smuzhiyun 	if (hoplimit == 0) {
114*4882a593Smuzhiyun 		struct net_device *dev = dst->dev;
115*4882a593Smuzhiyun 		struct inet6_dev *idev;
116*4882a593Smuzhiyun 
117*4882a593Smuzhiyun 		rcu_read_lock();
118*4882a593Smuzhiyun 		idev = __in6_dev_get(dev);
119*4882a593Smuzhiyun 		if (idev)
120*4882a593Smuzhiyun 			hoplimit = idev->cnf.hop_limit;
121*4882a593Smuzhiyun 		else
122*4882a593Smuzhiyun 			hoplimit = dev_net(dev)->ipv6.devconf_all->hop_limit;
123*4882a593Smuzhiyun 		rcu_read_unlock();
124*4882a593Smuzhiyun 	}
125*4882a593Smuzhiyun 	return hoplimit;
126*4882a593Smuzhiyun }
127*4882a593Smuzhiyun EXPORT_SYMBOL(ip6_dst_hoplimit);
128*4882a593Smuzhiyun #endif
129*4882a593Smuzhiyun 
__ip6_local_out(struct net * net,struct sock * sk,struct sk_buff * skb)130*4882a593Smuzhiyun int __ip6_local_out(struct net *net, struct sock *sk, struct sk_buff *skb)
131*4882a593Smuzhiyun {
132*4882a593Smuzhiyun 	int len;
133*4882a593Smuzhiyun 
134*4882a593Smuzhiyun 	len = skb->len - sizeof(struct ipv6hdr);
135*4882a593Smuzhiyun 	if (len > IPV6_MAXPLEN)
136*4882a593Smuzhiyun 		len = 0;
137*4882a593Smuzhiyun 	ipv6_hdr(skb)->payload_len = htons(len);
138*4882a593Smuzhiyun 	IP6CB(skb)->nhoff = offsetof(struct ipv6hdr, nexthdr);
139*4882a593Smuzhiyun 
140*4882a593Smuzhiyun 	/* if egress device is enslaved to an L3 master device pass the
141*4882a593Smuzhiyun 	 * skb to its handler for processing
142*4882a593Smuzhiyun 	 */
143*4882a593Smuzhiyun 	skb = l3mdev_ip6_out(sk, skb);
144*4882a593Smuzhiyun 	if (unlikely(!skb))
145*4882a593Smuzhiyun 		return 0;
146*4882a593Smuzhiyun 
147*4882a593Smuzhiyun 	skb->protocol = htons(ETH_P_IPV6);
148*4882a593Smuzhiyun 
149*4882a593Smuzhiyun 	return nf_hook(NFPROTO_IPV6, NF_INET_LOCAL_OUT,
150*4882a593Smuzhiyun 		       net, sk, skb, NULL, skb_dst(skb)->dev,
151*4882a593Smuzhiyun 		       dst_output);
152*4882a593Smuzhiyun }
153*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(__ip6_local_out);
154*4882a593Smuzhiyun 
ip6_local_out(struct net * net,struct sock * sk,struct sk_buff * skb)155*4882a593Smuzhiyun int ip6_local_out(struct net *net, struct sock *sk, struct sk_buff *skb)
156*4882a593Smuzhiyun {
157*4882a593Smuzhiyun 	int err;
158*4882a593Smuzhiyun 
159*4882a593Smuzhiyun 	err = __ip6_local_out(net, sk, skb);
160*4882a593Smuzhiyun 	if (likely(err == 1))
161*4882a593Smuzhiyun 		err = dst_output(net, sk, skb);
162*4882a593Smuzhiyun 
163*4882a593Smuzhiyun 	return err;
164*4882a593Smuzhiyun }
165*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(ip6_local_out);
166