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

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

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

~ [ 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