~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/net/ipv6/output_core.c

Version: ~ [ linux-5.15-rc5 ] ~ [ linux-5.14.11 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.72 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.152 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.210 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.250 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.286 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.288 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.18.140 ] ~ [ linux-3.16.85 ] ~ [ linux-3.14.79 ] ~ [ linux-3.12.74 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

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

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp