Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * IPv6 library code, needed by static components when full IPv6 support is
0004  * not configured or static.  These functions are needed by GSO/GRO implementation.
0005  */
0006 #include <linux/export.h>
0007 #include <net/ip.h>
0008 #include <net/ipv6.h>
0009 #include <net/ip6_fib.h>
0010 #include <net/addrconf.h>
0011 #include <net/secure_seq.h>
0012 #include <linux/netfilter.h>
0013 
0014 static u32 __ipv6_select_ident(struct net *net,
0015                    const struct in6_addr *dst,
0016                    const struct in6_addr *src)
0017 {
0018     u32 id;
0019 
0020     do {
0021         id = prandom_u32();
0022     } while (!id);
0023 
0024     return id;
0025 }
0026 
0027 /* This function exists only for tap drivers that must support broken
0028  * clients requesting UFO without specifying an IPv6 fragment ID.
0029  *
0030  * This is similar to ipv6_select_ident() but we use an independent hash
0031  * seed to limit information leakage.
0032  *
0033  * The network header must be set before calling this.
0034  */
0035 __be32 ipv6_proxy_select_ident(struct net *net, struct sk_buff *skb)
0036 {
0037     struct in6_addr buf[2];
0038     struct in6_addr *addrs;
0039     u32 id;
0040 
0041     addrs = skb_header_pointer(skb,
0042                    skb_network_offset(skb) +
0043                    offsetof(struct ipv6hdr, saddr),
0044                    sizeof(buf), buf);
0045     if (!addrs)
0046         return 0;
0047 
0048     id = __ipv6_select_ident(net, &addrs[1], &addrs[0]);
0049     return htonl(id);
0050 }
0051 EXPORT_SYMBOL_GPL(ipv6_proxy_select_ident);
0052 
0053 __be32 ipv6_select_ident(struct net *net,
0054              const struct in6_addr *daddr,
0055              const struct in6_addr *saddr)
0056 {
0057     u32 id;
0058 
0059     id = __ipv6_select_ident(net, daddr, saddr);
0060     return htonl(id);
0061 }
0062 EXPORT_SYMBOL(ipv6_select_ident);
0063 
0064 int ip6_find_1stfragopt(struct sk_buff *skb, u8 **nexthdr)
0065 {
0066     unsigned int offset = sizeof(struct ipv6hdr);
0067     unsigned int packet_len = skb_tail_pointer(skb) -
0068         skb_network_header(skb);
0069     int found_rhdr = 0;
0070     *nexthdr = &ipv6_hdr(skb)->nexthdr;
0071 
0072     while (offset <= packet_len) {
0073         struct ipv6_opt_hdr *exthdr;
0074 
0075         switch (**nexthdr) {
0076 
0077         case NEXTHDR_HOP:
0078             break;
0079         case NEXTHDR_ROUTING:
0080             found_rhdr = 1;
0081             break;
0082         case NEXTHDR_DEST:
0083 #if IS_ENABLED(CONFIG_IPV6_MIP6)
0084             if (ipv6_find_tlv(skb, offset, IPV6_TLV_HAO) >= 0)
0085                 break;
0086 #endif
0087             if (found_rhdr)
0088                 return offset;
0089             break;
0090         default:
0091             return offset;
0092         }
0093 
0094         if (offset + sizeof(struct ipv6_opt_hdr) > packet_len)
0095             return -EINVAL;
0096 
0097         exthdr = (struct ipv6_opt_hdr *)(skb_network_header(skb) +
0098                          offset);
0099         offset += ipv6_optlen(exthdr);
0100         if (offset > IPV6_MAXPLEN)
0101             return -EINVAL;
0102         *nexthdr = &exthdr->nexthdr;
0103     }
0104 
0105     return -EINVAL;
0106 }
0107 EXPORT_SYMBOL(ip6_find_1stfragopt);
0108 
0109 #if IS_ENABLED(CONFIG_IPV6)
0110 int ip6_dst_hoplimit(struct dst_entry *dst)
0111 {
0112     int hoplimit = dst_metric_raw(dst, RTAX_HOPLIMIT);
0113     if (hoplimit == 0) {
0114         struct net_device *dev = dst->dev;
0115         struct inet6_dev *idev;
0116 
0117         rcu_read_lock();
0118         idev = __in6_dev_get(dev);
0119         if (idev)
0120             hoplimit = idev->cnf.hop_limit;
0121         else
0122             hoplimit = dev_net(dev)->ipv6.devconf_all->hop_limit;
0123         rcu_read_unlock();
0124     }
0125     return hoplimit;
0126 }
0127 EXPORT_SYMBOL(ip6_dst_hoplimit);
0128 #endif
0129 
0130 int __ip6_local_out(struct net *net, struct sock *sk, struct sk_buff *skb)
0131 {
0132     int len;
0133 
0134     len = skb->len - sizeof(struct ipv6hdr);
0135     if (len > IPV6_MAXPLEN)
0136         len = 0;
0137     ipv6_hdr(skb)->payload_len = htons(len);
0138     IP6CB(skb)->nhoff = offsetof(struct ipv6hdr, nexthdr);
0139 
0140     /* if egress device is enslaved to an L3 master device pass the
0141      * skb to its handler for processing
0142      */
0143     skb = l3mdev_ip6_out(sk, skb);
0144     if (unlikely(!skb))
0145         return 0;
0146 
0147     skb->protocol = htons(ETH_P_IPV6);
0148 
0149     return nf_hook(NFPROTO_IPV6, NF_INET_LOCAL_OUT,
0150                net, sk, skb, NULL, skb_dst(skb)->dev,
0151                dst_output);
0152 }
0153 EXPORT_SYMBOL_GPL(__ip6_local_out);
0154 
0155 int ip6_local_out(struct net *net, struct sock *sk, struct sk_buff *skb)
0156 {
0157     int err;
0158 
0159     err = __ip6_local_out(net, sk, skb);
0160     if (likely(err == 1))
0161         err = dst_output(net, sk, skb);
0162 
0163     return err;
0164 }
0165 EXPORT_SYMBOL_GPL(ip6_local_out);