root/net/ipv6/output_core.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. __ipv6_select_ident
  2. ipv6_proxy_select_ident
  3. ipv6_select_ident
  4. ip6_find_1stfragopt
  5. ip6_dst_hoplimit
  6. __ip6_local_out
  7. ip6_local_out

   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         const struct {
  19                 struct in6_addr dst;
  20                 struct in6_addr src;
  21         } __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         if (unlikely(siphash_key_is_zero(&net->ipv4.ip_id_key)))
  29                 get_random_bytes(&net->ipv4.ip_id_key,
  30                                  sizeof(net->ipv4.ip_id_key));
  31 
  32         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         id = ip_idents_reserve(hash, 1);
  39         if (unlikely(!id))
  40                 id = 1 << 31;
  41 
  42         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 __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         addrs = skb_header_pointer(skb,
  60                                    skb_network_offset(skb) +
  61                                    offsetof(struct ipv6hdr, saddr),
  62                                    sizeof(buf), buf);
  63         if (!addrs)
  64                 return 0;
  65 
  66         id = __ipv6_select_ident(net, &addrs[1], &addrs[0]);
  67         return htonl(id);
  68 }
  69 EXPORT_SYMBOL_GPL(ipv6_proxy_select_ident);
  70 
  71 __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         id = __ipv6_select_ident(net, daddr, saddr);
  78         return htonl(id);
  79 }
  80 EXPORT_SYMBOL(ipv6_select_ident);
  81 
  82 int ip6_find_1stfragopt(struct sk_buff *skb, u8 **nexthdr)
  83 {
  84         unsigned int offset = sizeof(struct ipv6hdr);
  85         unsigned int packet_len = skb_tail_pointer(skb) -
  86                 skb_network_header(skb);
  87         int found_rhdr = 0;
  88         *nexthdr = &ipv6_hdr(skb)->nexthdr;
  89 
  90         while (offset <= packet_len) {
  91                 struct ipv6_opt_hdr *exthdr;
  92 
  93                 switch (**nexthdr) {
  94 
  95                 case NEXTHDR_HOP:
  96                         break;
  97                 case NEXTHDR_ROUTING:
  98                         found_rhdr = 1;
  99                         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                         if (found_rhdr)
 106                                 return offset;
 107                         break;
 108                 default:
 109                         return offset;
 110                 }
 111 
 112                 if (offset + sizeof(struct ipv6_opt_hdr) > packet_len)
 113                         return -EINVAL;
 114 
 115                 exthdr = (struct ipv6_opt_hdr *)(skb_network_header(skb) +
 116                                                  offset);
 117                 offset += ipv6_optlen(exthdr);
 118                 if (offset > IPV6_MAXPLEN)
 119                         return -EINVAL;
 120                 *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 int __ip6_local_out(struct net *net, struct sock *sk, struct sk_buff *skb)
 149 {
 150         int len;
 151 
 152         len = skb->len - sizeof(struct ipv6hdr);
 153         if (len > IPV6_MAXPLEN)
 154                 len = 0;
 155         ipv6_hdr(skb)->payload_len = htons(len);
 156         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         if (unlikely(!skb))
 163                 return 0;
 164 
 165         skb->protocol = htons(ETH_P_IPV6);
 166 
 167         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 int ip6_local_out(struct net *net, struct sock *sk, struct sk_buff *skb)
 174 {
 175         int err;
 176 
 177         err = __ip6_local_out(net, sk, skb);
 178         if (likely(err == 1))
 179                 err = dst_output(net, sk, skb);
 180 
 181         return err;
 182 }
 183 EXPORT_SYMBOL_GPL(ip6_local_out);

/* [<][>][^][v][top][bottom][index][help] */