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