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