0001
0002
0003
0004
0005
0006 #include <linux/export.h>
0007 #include <net/ip.h>
0008 #include <net/ipv6.h>
0009 #include <net/ip6_fib.h>
0010 #include <net/addrconf.h>
0011 #include <net/secure_seq.h>
0012 #include <linux/netfilter.h>
0013
0014 static u32 __ipv6_select_ident(struct net *net,
0015 const struct in6_addr *dst,
0016 const struct in6_addr *src)
0017 {
0018 u32 id;
0019
0020 do {
0021 id = prandom_u32();
0022 } while (!id);
0023
0024 return id;
0025 }
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035 __be32 ipv6_proxy_select_ident(struct net *net, struct sk_buff *skb)
0036 {
0037 struct in6_addr buf[2];
0038 struct in6_addr *addrs;
0039 u32 id;
0040
0041 addrs = skb_header_pointer(skb,
0042 skb_network_offset(skb) +
0043 offsetof(struct ipv6hdr, saddr),
0044 sizeof(buf), buf);
0045 if (!addrs)
0046 return 0;
0047
0048 id = __ipv6_select_ident(net, &addrs[1], &addrs[0]);
0049 return htonl(id);
0050 }
0051 EXPORT_SYMBOL_GPL(ipv6_proxy_select_ident);
0052
0053 __be32 ipv6_select_ident(struct net *net,
0054 const struct in6_addr *daddr,
0055 const struct in6_addr *saddr)
0056 {
0057 u32 id;
0058
0059 id = __ipv6_select_ident(net, daddr, saddr);
0060 return htonl(id);
0061 }
0062 EXPORT_SYMBOL(ipv6_select_ident);
0063
0064 int ip6_find_1stfragopt(struct sk_buff *skb, u8 **nexthdr)
0065 {
0066 unsigned int offset = sizeof(struct ipv6hdr);
0067 unsigned int packet_len = skb_tail_pointer(skb) -
0068 skb_network_header(skb);
0069 int found_rhdr = 0;
0070 *nexthdr = &ipv6_hdr(skb)->nexthdr;
0071
0072 while (offset <= packet_len) {
0073 struct ipv6_opt_hdr *exthdr;
0074
0075 switch (**nexthdr) {
0076
0077 case NEXTHDR_HOP:
0078 break;
0079 case NEXTHDR_ROUTING:
0080 found_rhdr = 1;
0081 break;
0082 case NEXTHDR_DEST:
0083 #if IS_ENABLED(CONFIG_IPV6_MIP6)
0084 if (ipv6_find_tlv(skb, offset, IPV6_TLV_HAO) >= 0)
0085 break;
0086 #endif
0087 if (found_rhdr)
0088 return offset;
0089 break;
0090 default:
0091 return offset;
0092 }
0093
0094 if (offset + sizeof(struct ipv6_opt_hdr) > packet_len)
0095 return -EINVAL;
0096
0097 exthdr = (struct ipv6_opt_hdr *)(skb_network_header(skb) +
0098 offset);
0099 offset += ipv6_optlen(exthdr);
0100 if (offset > IPV6_MAXPLEN)
0101 return -EINVAL;
0102 *nexthdr = &exthdr->nexthdr;
0103 }
0104
0105 return -EINVAL;
0106 }
0107 EXPORT_SYMBOL(ip6_find_1stfragopt);
0108
0109 #if IS_ENABLED(CONFIG_IPV6)
0110 int ip6_dst_hoplimit(struct dst_entry *dst)
0111 {
0112 int hoplimit = dst_metric_raw(dst, RTAX_HOPLIMIT);
0113 if (hoplimit == 0) {
0114 struct net_device *dev = dst->dev;
0115 struct inet6_dev *idev;
0116
0117 rcu_read_lock();
0118 idev = __in6_dev_get(dev);
0119 if (idev)
0120 hoplimit = idev->cnf.hop_limit;
0121 else
0122 hoplimit = dev_net(dev)->ipv6.devconf_all->hop_limit;
0123 rcu_read_unlock();
0124 }
0125 return hoplimit;
0126 }
0127 EXPORT_SYMBOL(ip6_dst_hoplimit);
0128 #endif
0129
0130 int __ip6_local_out(struct net *net, struct sock *sk, struct sk_buff *skb)
0131 {
0132 int len;
0133
0134 len = skb->len - sizeof(struct ipv6hdr);
0135 if (len > IPV6_MAXPLEN)
0136 len = 0;
0137 ipv6_hdr(skb)->payload_len = htons(len);
0138 IP6CB(skb)->nhoff = offsetof(struct ipv6hdr, nexthdr);
0139
0140
0141
0142
0143 skb = l3mdev_ip6_out(sk, skb);
0144 if (unlikely(!skb))
0145 return 0;
0146
0147 skb->protocol = htons(ETH_P_IPV6);
0148
0149 return nf_hook(NFPROTO_IPV6, NF_INET_LOCAL_OUT,
0150 net, sk, skb, NULL, skb_dst(skb)->dev,
0151 dst_output);
0152 }
0153 EXPORT_SYMBOL_GPL(__ip6_local_out);
0154
0155 int ip6_local_out(struct net *net, struct sock *sk, struct sk_buff *skb)
0156 {
0157 int err;
0158
0159 err = __ip6_local_out(net, sk, skb);
0160 if (likely(err == 1))
0161 err = dst_output(net, sk, skb);
0162
0163 return err;
0164 }
0165 EXPORT_SYMBOL_GPL(ip6_local_out);