@@ -110,8 +110,19 @@ void udp_v6_rehash(struct sock *sk)
110110 u16 new_hash = ipv6_portaddr_hash (sock_net (sk ),
111111 & sk -> sk_v6_rcv_saddr ,
112112 inet_sk (sk )-> inet_num );
113+ u16 new_hash4 ;
113114
114- udp_lib_rehash (sk , new_hash , 0 ); /* 4-tuple hash not implemented */
115+ if (ipv6_addr_v4mapped (& sk -> sk_v6_rcv_saddr )) {
116+ new_hash4 = udp_ehashfn (sock_net (sk ),
117+ sk -> sk_rcv_saddr , sk -> sk_num ,
118+ sk -> sk_daddr , sk -> sk_dport );
119+ } else {
120+ new_hash4 = udp6_ehashfn (sock_net (sk ),
121+ & sk -> sk_v6_rcv_saddr , sk -> sk_num ,
122+ & sk -> sk_v6_daddr , sk -> sk_dport );
123+ }
124+
125+ udp_lib_rehash (sk , new_hash , new_hash4 );
115126}
116127
117128static int compute_score (struct sock * sk , const struct net * net ,
@@ -216,6 +227,74 @@ static struct sock *udp6_lib_lookup2(const struct net *net,
216227 return result ;
217228}
218229
230+ #if IS_ENABLED (CONFIG_BASE_SMALL )
231+ static struct sock * udp6_lib_lookup4 (const struct net * net ,
232+ const struct in6_addr * saddr , __be16 sport ,
233+ const struct in6_addr * daddr ,
234+ unsigned int hnum , int dif , int sdif ,
235+ struct udp_table * udptable )
236+ {
237+ return NULL ;
238+ }
239+
240+ static void udp6_hash4 (struct sock * sk )
241+ {
242+ }
243+ #else /* !CONFIG_BASE_SMALL */
244+ static struct sock * udp6_lib_lookup4 (const struct net * net ,
245+ const struct in6_addr * saddr , __be16 sport ,
246+ const struct in6_addr * daddr ,
247+ unsigned int hnum , int dif , int sdif ,
248+ struct udp_table * udptable )
249+ {
250+ const __portpair ports = INET_COMBINED_PORTS (sport , hnum );
251+ const struct hlist_nulls_node * node ;
252+ struct udp_hslot * hslot4 ;
253+ unsigned int hash4 , slot ;
254+ struct udp_sock * up ;
255+ struct sock * sk ;
256+
257+ hash4 = udp6_ehashfn (net , daddr , hnum , saddr , sport );
258+ slot = hash4 & udptable -> mask ;
259+ hslot4 = & udptable -> hash4 [slot ];
260+
261+ begin :
262+ udp_lrpa_for_each_entry_rcu (up , node , & hslot4 -> nulls_head ) {
263+ sk = (struct sock * )up ;
264+ if (inet6_match (net , sk , saddr , daddr , ports , dif , sdif ))
265+ return sk ;
266+ }
267+
268+ /* if the nulls value we got at the end of this lookup is not the
269+ * expected one, we must restart lookup. We probably met an item that
270+ * was moved to another chain due to rehash.
271+ */
272+ if (get_nulls_value (node ) != slot )
273+ goto begin ;
274+
275+ return NULL ;
276+ }
277+
278+ static void udp6_hash4 (struct sock * sk )
279+ {
280+ struct net * net = sock_net (sk );
281+ unsigned int hash ;
282+
283+ if (ipv6_addr_v4mapped (& sk -> sk_v6_rcv_saddr )) {
284+ udp4_hash4 (sk );
285+ return ;
286+ }
287+
288+ if (sk_unhashed (sk ) || ipv6_addr_any (& sk -> sk_v6_rcv_saddr ))
289+ return ;
290+
291+ hash = udp6_ehashfn (net , & sk -> sk_v6_rcv_saddr , sk -> sk_num ,
292+ & sk -> sk_v6_daddr , sk -> sk_dport );
293+
294+ udp_lib_hash4 (sk , hash );
295+ }
296+ #endif /* CONFIG_BASE_SMALL */
297+
219298/* rcu_read_lock() must be held */
220299struct sock * __udp6_lib_lookup (const struct net * net ,
221300 const struct in6_addr * saddr , __be16 sport ,
@@ -231,6 +310,13 @@ struct sock *__udp6_lib_lookup(const struct net *net,
231310 hash2 = ipv6_portaddr_hash (net , daddr , hnum );
232311 hslot2 = udp_hashslot2 (udptable , hash2 );
233312
313+ if (udp_has_hash4 (hslot2 )) {
314+ result = udp6_lib_lookup4 (net , saddr , sport , daddr , hnum ,
315+ dif , sdif , udptable );
316+ if (result ) /* udp6_lib_lookup4 return sk or NULL */
317+ return result ;
318+ }
319+
234320 /* Lookup connected or non-wildcard sockets */
235321 result = udp6_lib_lookup2 (net , saddr , sport ,
236322 daddr , hnum , dif , sdif ,
@@ -1166,6 +1252,18 @@ static int udpv6_pre_connect(struct sock *sk, struct sockaddr *uaddr,
11661252 return BPF_CGROUP_RUN_PROG_INET6_CONNECT_LOCK (sk , uaddr , & addr_len );
11671253}
11681254
1255+ static int udpv6_connect (struct sock * sk , struct sockaddr * uaddr , int addr_len )
1256+ {
1257+ int res ;
1258+
1259+ lock_sock (sk );
1260+ res = __ip6_datagram_connect (sk , uaddr , addr_len );
1261+ if (!res )
1262+ udp6_hash4 (sk );
1263+ release_sock (sk );
1264+ return res ;
1265+ }
1266+
11691267/**
11701268 * udp6_hwcsum_outgoing - handle outgoing HW checksumming
11711269 * @sk: socket we are sending on
@@ -1761,7 +1859,7 @@ struct proto udpv6_prot = {
17611859 .owner = THIS_MODULE ,
17621860 .close = udp_lib_close ,
17631861 .pre_connect = udpv6_pre_connect ,
1764- .connect = ip6_datagram_connect ,
1862+ .connect = udpv6_connect ,
17651863 .disconnect = udp_disconnect ,
17661864 .ioctl = udp_ioctl ,
17671865 .init = udpv6_init_sock ,
0 commit comments