LCOV - code coverage report
Current view: top level - net/ipv6 - output_core.c (source / functions) Hit Total Coverage
Test: gcov_data_raspi2_qemu_modules_combined.info Lines: 19 51 37.3 %
Date: 2020-09-30 20:25:01 Functions: 3 7 42.9 %
Branches: 5 28 17.9 %

           Branch data     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                 :            :         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                 :            :         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                 :            :                 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                 :            :         struct in6_addr buf[2];
      56                 :            :         struct in6_addr *addrs;
      57                 :            :         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                 :            :         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                 :            :         unsigned int offset = sizeof(struct ipv6hdr);
      85                 :          0 :         unsigned int packet_len = skb_tail_pointer(skb) -
      86                 :            :                 skb_network_header(skb);
      87                 :            :         int found_rhdr = 0;
      88                 :          0 :         *nexthdr = &ipv6_hdr(skb)->nexthdr;
      89                 :            : 
      90         [ #  # ]:          0 :         while (offset <= packet_len) {
      91                 :            :                 struct ipv6_opt_hdr *exthdr;
      92                 :            : 
      93   [ #  #  #  # ]:          0 :                 switch (**nexthdr) {
      94                 :            : 
      95                 :            :                 case NEXTHDR_HOP:
      96                 :            :                         break;
      97                 :            :                 case NEXTHDR_ROUTING:
      98                 :            :                         found_rhdr = 1;
      99                 :          0 :                         break;
     100                 :            :                 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                 :            :                 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                 :         16 : int ip6_dst_hoplimit(struct dst_entry *dst)
     129                 :            : {
     130                 :         16 :         int hoplimit = dst_metric_raw(dst, RTAX_HOPLIMIT);
     131         [ +  - ]:         16 :         if (hoplimit == 0) {
     132                 :         16 :                 struct net_device *dev = dst->dev;
     133                 :            :                 struct inet6_dev *idev;
     134                 :            : 
     135                 :            :                 rcu_read_lock();
     136                 :            :                 idev = __in6_dev_get(dev);
     137         [ +  - ]:         16 :                 if (idev)
     138                 :         16 :                         hoplimit = idev->cnf.hop_limit;
     139                 :            :                 else
     140                 :          0 :                         hoplimit = dev_net(dev)->ipv6.devconf_all->hop_limit;
     141                 :            :                 rcu_read_unlock();
     142                 :            :         }
     143                 :         16 :         return hoplimit;
     144                 :            : }
     145                 :            : EXPORT_SYMBOL(ip6_dst_hoplimit);
     146                 :            : #endif
     147                 :            : 
     148                 :       2060 : int __ip6_local_out(struct net *net, struct sock *sk, struct sk_buff *skb)
     149                 :            : {
     150                 :            :         int len;
     151                 :            : 
     152                 :       2060 :         len = skb->len - sizeof(struct ipv6hdr);
     153         [ -  + ]:       2060 :         if (len > IPV6_MAXPLEN)
     154                 :            :                 len = 0;
     155                 :       2060 :         ipv6_hdr(skb)->payload_len = htons(len);
     156                 :       2060 :         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                 :            :         skb = l3mdev_ip6_out(sk, skb);
     162         [ +  - ]:       2060 :         if (unlikely(!skb))
     163                 :            :                 return 0;
     164                 :            : 
     165                 :       2060 :         skb->protocol = htons(ETH_P_IPV6);
     166                 :            : 
     167                 :       2060 :         return nf_hook(NFPROTO_IPV6, NF_INET_LOCAL_OUT,
     168                 :            :                        net, sk, skb, NULL, skb_dst(skb)->dev,
     169                 :            :                        dst_output);
     170                 :            : }
     171                 :            : EXPORT_SYMBOL_GPL(__ip6_local_out);
     172                 :            : 
     173                 :       2060 : int ip6_local_out(struct net *net, struct sock *sk, struct sk_buff *skb)
     174                 :            : {
     175                 :            :         int err;
     176                 :            : 
     177                 :       2060 :         err = __ip6_local_out(net, sk, skb);
     178         [ +  - ]:       2060 :         if (likely(err == 1))
     179                 :            :                 err = dst_output(net, sk, skb);
     180                 :            : 
     181                 :       2060 :         return err;
     182                 :            : }
     183                 :            : EXPORT_SYMBOL_GPL(ip6_local_out);

Generated by: LCOV version 1.14