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 : 1 : int ip6_dst_hoplimit(struct dst_entry *dst) 129 : : { 130 : 1 : int hoplimit = dst_metric_raw(dst, RTAX_HOPLIMIT); 131 : 1 : if (hoplimit == 0) { 132 : 1 : struct net_device *dev = dst->dev; 133 : : struct inet6_dev *idev; 134 : : 135 : : rcu_read_lock(); 136 : : idev = __in6_dev_get(dev); 137 : 1 : if (idev) 138 : 1 : hoplimit = idev->cnf.hop_limit; 139 : : else 140 : 0 : hoplimit = dev_net(dev)->ipv6.devconf_all->hop_limit; 141 : : rcu_read_unlock(); 142 : : } 143 : 1 : return hoplimit; 144 : : } 145 : : EXPORT_SYMBOL(ip6_dst_hoplimit); 146 : : #endif 147 : : 148 : 3 : int __ip6_local_out(struct net *net, struct sock *sk, struct sk_buff *skb) 149 : : { 150 : : int len; 151 : : 152 : 3 : len = skb->len - sizeof(struct ipv6hdr); 153 : 3 : if (len > IPV6_MAXPLEN) 154 : : len = 0; 155 : 3 : ipv6_hdr(skb)->payload_len = htons(len); 156 : 3 : 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 : 3 : if (unlikely(!skb)) 163 : : return 0; 164 : : 165 : 3 : skb->protocol = htons(ETH_P_IPV6); 166 : : 167 : 3 : 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 : 3 : int ip6_local_out(struct net *net, struct sock *sk, struct sk_buff *skb) 174 : : { 175 : : int err; 176 : : 177 : 3 : err = __ip6_local_out(net, sk, skb); 178 : 3 : if (likely(err == 1)) 179 : : err = dst_output(net, sk, skb); 180 : : 181 : 3 : return err; 182 : : } 183 : : EXPORT_SYMBOL_GPL(ip6_local_out);