LCOV - code coverage report
Current view: top level - net/ipv6 - output_core.c (source / functions) Hit Total Coverage
Test: landlock.info Lines: 0 64 0.0 %
Date: 2021-04-22 12:43:58 Functions: 0 6 0.0 %

          Line data    Source code
       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           0 : static u32 __ipv6_select_ident(struct net *net,
      15             :                                const struct in6_addr *dst,
      16             :                                const struct in6_addr *src)
      17             : {
      18           0 :         const struct {
      19             :                 struct in6_addr dst;
      20             :                 struct in6_addr src;
      21           0 :         } __aligned(SIPHASH_ALIGNMENT) combined = {
      22             :                 .dst = *dst,
      23             :                 .src = *src,
      24             :         };
      25           0 :         u32 hash, id;
      26             : 
      27             :         /* Note the following code is not safe, but this is okay. */
      28           0 :         if (unlikely(siphash_key_is_zero(&net->ipv4.ip_id_key)))
      29           0 :                 get_random_bytes(&net->ipv4.ip_id_key,
      30             :                                  sizeof(net->ipv4.ip_id_key));
      31             : 
      32           0 :         hash = siphash(&combined, sizeof(combined), &net->ipv4.ip_id_key);
      33             : 
      34             :         /* Treat id of 0 as unset and if we get 0 back from ip_idents_reserve,
      35             :          * set the hight order instead thus minimizing possible future
      36             :          * collisions.
      37             :          */
      38           0 :         id = ip_idents_reserve(hash, 1);
      39           0 :         if (unlikely(!id))
      40           0 :                 id = 1 << 31;
      41             : 
      42           0 :         return id;
      43             : }
      44             : 
      45             : /* This function exists only for tap drivers that must support broken
      46             :  * clients requesting UFO without specifying an IPv6 fragment ID.
      47             :  *
      48             :  * This is similar to ipv6_select_ident() but we use an independent hash
      49             :  * seed to limit information leakage.
      50             :  *
      51             :  * The network header must be set before calling this.
      52             :  */
      53           0 : __be32 ipv6_proxy_select_ident(struct net *net, struct sk_buff *skb)
      54             : {
      55           0 :         struct in6_addr buf[2];
      56           0 :         struct in6_addr *addrs;
      57           0 :         u32 id;
      58             : 
      59           0 :         addrs = skb_header_pointer(skb,
      60           0 :                                    skb_network_offset(skb) +
      61             :                                    offsetof(struct ipv6hdr, saddr),
      62             :                                    sizeof(buf), buf);
      63           0 :         if (!addrs)
      64             :                 return 0;
      65             : 
      66           0 :         id = __ipv6_select_ident(net, &addrs[1], &addrs[0]);
      67           0 :         return htonl(id);
      68             : }
      69             : EXPORT_SYMBOL_GPL(ipv6_proxy_select_ident);
      70             : 
      71           0 : __be32 ipv6_select_ident(struct net *net,
      72             :                          const struct in6_addr *daddr,
      73             :                          const struct in6_addr *saddr)
      74             : {
      75           0 :         u32 id;
      76             : 
      77           0 :         id = __ipv6_select_ident(net, daddr, saddr);
      78           0 :         return htonl(id);
      79             : }
      80             : EXPORT_SYMBOL(ipv6_select_ident);
      81             : 
      82           0 : int ip6_find_1stfragopt(struct sk_buff *skb, u8 **nexthdr)
      83             : {
      84           0 :         unsigned int offset = sizeof(struct ipv6hdr);
      85           0 :         unsigned int packet_len = skb_tail_pointer(skb) -
      86           0 :                 skb_network_header(skb);
      87           0 :         int found_rhdr = 0;
      88           0 :         *nexthdr = &ipv6_hdr(skb)->nexthdr;
      89             : 
      90           0 :         while (offset <= packet_len) {
      91           0 :                 struct ipv6_opt_hdr *exthdr;
      92             : 
      93           0 :                 switch (**nexthdr) {
      94             : 
      95             :                 case NEXTHDR_HOP:
      96             :                         break;
      97           0 :                 case NEXTHDR_ROUTING:
      98           0 :                         found_rhdr = 1;
      99           0 :                         break;
     100           0 :                 case NEXTHDR_DEST:
     101             : #if IS_ENABLED(CONFIG_IPV6_MIP6)
     102             :                         if (ipv6_find_tlv(skb, offset, IPV6_TLV_HAO) >= 0)
     103             :                                 break;
     104             : #endif
     105           0 :                         if (found_rhdr)
     106           0 :                                 return offset;
     107             :                         break;
     108           0 :                 default:
     109           0 :                         return offset;
     110             :                 }
     111             : 
     112           0 :                 if (offset + sizeof(struct ipv6_opt_hdr) > packet_len)
     113             :                         return -EINVAL;
     114             : 
     115           0 :                 exthdr = (struct ipv6_opt_hdr *)(skb_network_header(skb) +
     116             :                                                  offset);
     117           0 :                 offset += ipv6_optlen(exthdr);
     118           0 :                 if (offset > IPV6_MAXPLEN)
     119             :                         return -EINVAL;
     120           0 :                 *nexthdr = &exthdr->nexthdr;
     121             :         }
     122             : 
     123             :         return -EINVAL;
     124             : }
     125             : EXPORT_SYMBOL(ip6_find_1stfragopt);
     126             : 
     127             : #if IS_ENABLED(CONFIG_IPV6)
     128             : int ip6_dst_hoplimit(struct dst_entry *dst)
     129             : {
     130             :         int hoplimit = dst_metric_raw(dst, RTAX_HOPLIMIT);
     131             :         if (hoplimit == 0) {
     132             :                 struct net_device *dev = dst->dev;
     133             :                 struct inet6_dev *idev;
     134             : 
     135             :                 rcu_read_lock();
     136             :                 idev = __in6_dev_get(dev);
     137             :                 if (idev)
     138             :                         hoplimit = idev->cnf.hop_limit;
     139             :                 else
     140             :                         hoplimit = dev_net(dev)->ipv6.devconf_all->hop_limit;
     141             :                 rcu_read_unlock();
     142             :         }
     143             :         return hoplimit;
     144             : }
     145             : EXPORT_SYMBOL(ip6_dst_hoplimit);
     146             : #endif
     147             : 
     148           0 : int __ip6_local_out(struct net *net, struct sock *sk, struct sk_buff *skb)
     149             : {
     150           0 :         int len;
     151             : 
     152           0 :         len = skb->len - sizeof(struct ipv6hdr);
     153           0 :         if (len > IPV6_MAXPLEN)
     154           0 :                 len = 0;
     155           0 :         ipv6_hdr(skb)->payload_len = htons(len);
     156           0 :         IP6CB(skb)->nhoff = offsetof(struct ipv6hdr, nexthdr);
     157             : 
     158             :         /* if egress device is enslaved to an L3 master device pass the
     159             :          * skb to its handler for processing
     160             :          */
     161           0 :         skb = l3mdev_ip6_out(sk, skb);
     162           0 :         if (unlikely(!skb))
     163             :                 return 0;
     164             : 
     165           0 :         skb->protocol = htons(ETH_P_IPV6);
     166             : 
     167           0 :         return nf_hook(NFPROTO_IPV6, NF_INET_LOCAL_OUT,
     168           0 :                        net, sk, skb, NULL, skb_dst(skb)->dev,
     169             :                        dst_output);
     170             : }
     171             : EXPORT_SYMBOL_GPL(__ip6_local_out);
     172             : 
     173           0 : int ip6_local_out(struct net *net, struct sock *sk, struct sk_buff *skb)
     174             : {
     175           0 :         int err;
     176             : 
     177           0 :         err = __ip6_local_out(net, sk, skb);
     178           0 :         if (likely(err == 1))
     179           0 :                 err = dst_output(net, sk, skb);
     180             : 
     181           0 :         return err;
     182             : }
     183             : EXPORT_SYMBOL_GPL(ip6_local_out);

Generated by: LCOV version 1.14