1 /* SPDX-License-Identifier: GPL-2.0-or-later */ 2 /* 3 * INET An implementation of the TCP/IP protocol suite for the LINUX 4 * operating system. INET is implemented using the BSD Socket 5 * interface as the means of communication with the user level. 6 * 7 * Authors: Lotsa people, from code originally in tcp 8 */ 9 10 #ifndef _INET6_HASHTABLES_H 11 #define _INET6_HASHTABLES_H 12 13 14 #if IS_ENABLED(CONFIG_IPV6) 15 #include <linux/in6.h> 16 #include <linux/ipv6.h> 17 #include <linux/types.h> 18 #include <linux/jhash.h> 19 20 #include <net/inet_sock.h> 21 22 #include <net/ipv6.h> 23 #include <net/netns/hash.h> 24 25 struct inet_hashinfo; 26 27 void inet6_init_ehash_secret(void); 28 29 static inline unsigned int __inet6_ehashfn(const u32 lhash, 30 const u16 lport, 31 const u32 fhash, 32 const __be16 fport, 33 const u32 initval) 34 { 35 const u32 ports = (((u32)lport) << 16) | (__force u32)fport; 36 return jhash_3words(lhash, fhash, ports, initval); 37 } 38 39 /* 40 * Sockets in TCP_CLOSE state are _always_ taken out of the hash, so 41 * we need not check it for TCP lookups anymore, thanks Alexey. -DaveM 42 * 43 * The sockhash lock must be held as a reader here. 44 */ 45 struct sock *__inet6_lookup_established(const struct net *net, 46 const struct in6_addr *saddr, 47 const __be16 sport, 48 const struct in6_addr *daddr, 49 const u16 hnum, const int dif, 50 const int sdif); 51 52 typedef u32 (inet6_ehashfn_t)(const struct net *net, 53 const struct in6_addr *laddr, const u16 lport, 54 const struct in6_addr *faddr, const __be16 fport); 55 56 inet6_ehashfn_t inet6_ehashfn; 57 58 INDIRECT_CALLABLE_DECLARE(inet6_ehashfn_t udp6_ehashfn); 59 60 struct sock *inet6_lookup_reuseport(const struct net *net, struct sock *sk, 61 struct sk_buff *skb, int doff, 62 const struct in6_addr *saddr, 63 __be16 sport, 64 const struct in6_addr *daddr, 65 unsigned short hnum, 66 inet6_ehashfn_t *ehashfn); 67 68 struct sock *inet6_lookup_listener(const struct net *net, 69 struct sk_buff *skb, int doff, 70 const struct in6_addr *saddr, 71 const __be16 sport, 72 const struct in6_addr *daddr, 73 const unsigned short hnum, 74 const int dif, const int sdif); 75 76 struct sock *inet6_lookup_run_sk_lookup(const struct net *net, 77 int protocol, 78 struct sk_buff *skb, int doff, 79 const struct in6_addr *saddr, 80 const __be16 sport, 81 const struct in6_addr *daddr, 82 const u16 hnum, const int dif, 83 inet6_ehashfn_t *ehashfn); 84 85 static inline struct sock *__inet6_lookup(const struct net *net, 86 struct sk_buff *skb, int doff, 87 const struct in6_addr *saddr, 88 const __be16 sport, 89 const struct in6_addr *daddr, 90 const u16 hnum, 91 const int dif, const int sdif, 92 bool *refcounted) 93 { 94 struct sock *sk = __inet6_lookup_established(net, saddr, sport, 95 daddr, hnum, 96 dif, sdif); 97 *refcounted = true; 98 if (sk) 99 return sk; 100 *refcounted = false; 101 return inet6_lookup_listener(net, skb, doff, saddr, sport, 102 daddr, hnum, dif, sdif); 103 } 104 105 static inline 106 struct sock *inet6_steal_sock(struct net *net, struct sk_buff *skb, int doff, 107 const struct in6_addr *saddr, const __be16 sport, 108 const struct in6_addr *daddr, const __be16 dport, 109 bool *refcounted, inet6_ehashfn_t *ehashfn) 110 { 111 struct sock *sk, *reuse_sk; 112 bool prefetched; 113 114 sk = skb_steal_sock(skb, refcounted, &prefetched); 115 if (!sk) 116 return NULL; 117 118 if (!prefetched || !sk_fullsock(sk)) 119 return sk; 120 121 if (sk->sk_protocol == IPPROTO_TCP) { 122 if (sk->sk_state != TCP_LISTEN) 123 return sk; 124 } else if (sk->sk_protocol == IPPROTO_UDP) { 125 if (sk->sk_state != TCP_CLOSE) 126 return sk; 127 } else { 128 return sk; 129 } 130 131 reuse_sk = inet6_lookup_reuseport(net, sk, skb, doff, 132 saddr, sport, daddr, ntohs(dport), 133 ehashfn); 134 if (!reuse_sk) 135 return sk; 136 137 /* We've chosen a new reuseport sock which is never refcounted. This 138 * implies that sk also isn't refcounted. 139 */ 140 WARN_ON_ONCE(*refcounted); 141 142 return reuse_sk; 143 } 144 145 static inline struct sock *__inet6_lookup_skb(struct sk_buff *skb, int doff, 146 const __be16 sport, 147 const __be16 dport, 148 int iif, int sdif, 149 bool *refcounted) 150 { 151 struct net *net = skb_dst_dev_net_rcu(skb); 152 const struct ipv6hdr *ip6h = ipv6_hdr(skb); 153 struct sock *sk; 154 155 sk = inet6_steal_sock(net, skb, doff, &ip6h->saddr, sport, &ip6h->daddr, dport, 156 refcounted, inet6_ehashfn); 157 if (IS_ERR(sk)) 158 return NULL; 159 if (sk) 160 return sk; 161 162 return __inet6_lookup(net, skb, doff, &ip6h->saddr, sport, 163 &ip6h->daddr, ntohs(dport), 164 iif, sdif, refcounted); 165 } 166 167 struct sock *inet6_lookup(const struct net *net, struct sk_buff *skb, int doff, 168 const struct in6_addr *saddr, const __be16 sport, 169 const struct in6_addr *daddr, const __be16 dport, 170 const int dif); 171 172 static inline bool inet6_match(const struct net *net, const struct sock *sk, 173 const struct in6_addr *saddr, 174 const struct in6_addr *daddr, 175 const __portpair ports, 176 const int dif, const int sdif) 177 { 178 if (!net_eq(sock_net(sk), net) || 179 sk->sk_family != AF_INET6 || 180 READ_ONCE(sk->sk_portpair) != ports || 181 !ipv6_addr_equal(&sk->sk_v6_daddr, saddr) || 182 !ipv6_addr_equal(&sk->sk_v6_rcv_saddr, daddr)) 183 return false; 184 185 /* READ_ONCE() paired with WRITE_ONCE() in sock_bindtoindex_locked() */ 186 return inet_sk_bound_dev_eq(net, READ_ONCE(sk->sk_bound_dev_if), dif, 187 sdif); 188 } 189 #endif /* IS_ENABLED(CONFIG_IPV6) */ 190 191 #endif /* _INET6_HASHTABLES_H */ 192