f2fs: Provide a splice-read wrapper
[linux-block.git] / net / ipv6 / output_core.c
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
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  */
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
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
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)
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 = idev->cnf.hop_limit;
115                 else
116                         hoplimit = 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
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
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);