18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */ 28c2ecf20Sopenharmony_ci#ifndef _XFRM_HASH_H 38c2ecf20Sopenharmony_ci#define _XFRM_HASH_H 48c2ecf20Sopenharmony_ci 58c2ecf20Sopenharmony_ci#include <linux/xfrm.h> 68c2ecf20Sopenharmony_ci#include <linux/socket.h> 78c2ecf20Sopenharmony_ci#include <linux/jhash.h> 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_cistatic inline unsigned int __xfrm4_addr_hash(const xfrm_address_t *addr) 108c2ecf20Sopenharmony_ci{ 118c2ecf20Sopenharmony_ci return ntohl(addr->a4); 128c2ecf20Sopenharmony_ci} 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_cistatic inline unsigned int __xfrm6_addr_hash(const xfrm_address_t *addr) 158c2ecf20Sopenharmony_ci{ 168c2ecf20Sopenharmony_ci return jhash2((__force u32 *)addr->a6, 4, 0); 178c2ecf20Sopenharmony_ci} 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_cistatic inline unsigned int __xfrm4_daddr_saddr_hash(const xfrm_address_t *daddr, 208c2ecf20Sopenharmony_ci const xfrm_address_t *saddr) 218c2ecf20Sopenharmony_ci{ 228c2ecf20Sopenharmony_ci u32 sum = (__force u32)daddr->a4 + (__force u32)saddr->a4; 238c2ecf20Sopenharmony_ci return ntohl((__force __be32)sum); 248c2ecf20Sopenharmony_ci} 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_cistatic inline unsigned int __xfrm6_daddr_saddr_hash(const xfrm_address_t *daddr, 278c2ecf20Sopenharmony_ci const xfrm_address_t *saddr) 288c2ecf20Sopenharmony_ci{ 298c2ecf20Sopenharmony_ci return __xfrm6_addr_hash(daddr) ^ __xfrm6_addr_hash(saddr); 308c2ecf20Sopenharmony_ci} 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_cistatic inline u32 __bits2mask32(__u8 bits) 338c2ecf20Sopenharmony_ci{ 348c2ecf20Sopenharmony_ci u32 mask32 = 0xffffffff; 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci if (bits == 0) 378c2ecf20Sopenharmony_ci mask32 = 0; 388c2ecf20Sopenharmony_ci else if (bits < 32) 398c2ecf20Sopenharmony_ci mask32 <<= (32 - bits); 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci return mask32; 428c2ecf20Sopenharmony_ci} 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_cistatic inline unsigned int __xfrm4_dpref_spref_hash(const xfrm_address_t *daddr, 458c2ecf20Sopenharmony_ci const xfrm_address_t *saddr, 468c2ecf20Sopenharmony_ci __u8 dbits, 478c2ecf20Sopenharmony_ci __u8 sbits) 488c2ecf20Sopenharmony_ci{ 498c2ecf20Sopenharmony_ci return jhash_2words(ntohl(daddr->a4) & __bits2mask32(dbits), 508c2ecf20Sopenharmony_ci ntohl(saddr->a4) & __bits2mask32(sbits), 518c2ecf20Sopenharmony_ci 0); 528c2ecf20Sopenharmony_ci} 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_cistatic inline unsigned int __xfrm6_pref_hash(const xfrm_address_t *addr, 558c2ecf20Sopenharmony_ci __u8 prefixlen) 568c2ecf20Sopenharmony_ci{ 578c2ecf20Sopenharmony_ci unsigned int pdw; 588c2ecf20Sopenharmony_ci unsigned int pbi; 598c2ecf20Sopenharmony_ci u32 initval = 0; 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci pdw = prefixlen >> 5; /* num of whole u32 in prefix */ 628c2ecf20Sopenharmony_ci pbi = prefixlen & 0x1f; /* num of bits in incomplete u32 in prefix */ 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci if (pbi) { 658c2ecf20Sopenharmony_ci __be32 mask; 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci mask = htonl((0xffffffff) << (32 - pbi)); 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci initval = (__force u32)(addr->a6[pdw] & mask); 708c2ecf20Sopenharmony_ci } 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci return jhash2((__force u32 *)addr->a6, pdw, initval); 738c2ecf20Sopenharmony_ci} 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_cistatic inline unsigned int __xfrm6_dpref_spref_hash(const xfrm_address_t *daddr, 768c2ecf20Sopenharmony_ci const xfrm_address_t *saddr, 778c2ecf20Sopenharmony_ci __u8 dbits, 788c2ecf20Sopenharmony_ci __u8 sbits) 798c2ecf20Sopenharmony_ci{ 808c2ecf20Sopenharmony_ci return __xfrm6_pref_hash(daddr, dbits) ^ 818c2ecf20Sopenharmony_ci __xfrm6_pref_hash(saddr, sbits); 828c2ecf20Sopenharmony_ci} 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_cistatic inline unsigned int __xfrm_dst_hash(const xfrm_address_t *daddr, 858c2ecf20Sopenharmony_ci const xfrm_address_t *saddr, 868c2ecf20Sopenharmony_ci u32 reqid, unsigned short family, 878c2ecf20Sopenharmony_ci unsigned int hmask) 888c2ecf20Sopenharmony_ci{ 898c2ecf20Sopenharmony_ci unsigned int h = family ^ reqid; 908c2ecf20Sopenharmony_ci switch (family) { 918c2ecf20Sopenharmony_ci case AF_INET: 928c2ecf20Sopenharmony_ci h ^= __xfrm4_daddr_saddr_hash(daddr, saddr); 938c2ecf20Sopenharmony_ci break; 948c2ecf20Sopenharmony_ci case AF_INET6: 958c2ecf20Sopenharmony_ci h ^= __xfrm6_daddr_saddr_hash(daddr, saddr); 968c2ecf20Sopenharmony_ci break; 978c2ecf20Sopenharmony_ci } 988c2ecf20Sopenharmony_ci return (h ^ (h >> 16)) & hmask; 998c2ecf20Sopenharmony_ci} 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_cistatic inline unsigned int __xfrm_src_hash(const xfrm_address_t *daddr, 1028c2ecf20Sopenharmony_ci const xfrm_address_t *saddr, 1038c2ecf20Sopenharmony_ci unsigned short family, 1048c2ecf20Sopenharmony_ci unsigned int hmask) 1058c2ecf20Sopenharmony_ci{ 1068c2ecf20Sopenharmony_ci unsigned int h = family; 1078c2ecf20Sopenharmony_ci switch (family) { 1088c2ecf20Sopenharmony_ci case AF_INET: 1098c2ecf20Sopenharmony_ci h ^= __xfrm4_daddr_saddr_hash(daddr, saddr); 1108c2ecf20Sopenharmony_ci break; 1118c2ecf20Sopenharmony_ci case AF_INET6: 1128c2ecf20Sopenharmony_ci h ^= __xfrm6_daddr_saddr_hash(daddr, saddr); 1138c2ecf20Sopenharmony_ci break; 1148c2ecf20Sopenharmony_ci } 1158c2ecf20Sopenharmony_ci return (h ^ (h >> 16)) & hmask; 1168c2ecf20Sopenharmony_ci} 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_cistatic inline unsigned int 1198c2ecf20Sopenharmony_ci__xfrm_spi_hash(const xfrm_address_t *daddr, __be32 spi, u8 proto, 1208c2ecf20Sopenharmony_ci unsigned short family, unsigned int hmask) 1218c2ecf20Sopenharmony_ci{ 1228c2ecf20Sopenharmony_ci unsigned int h = (__force u32)spi ^ proto; 1238c2ecf20Sopenharmony_ci switch (family) { 1248c2ecf20Sopenharmony_ci case AF_INET: 1258c2ecf20Sopenharmony_ci h ^= __xfrm4_addr_hash(daddr); 1268c2ecf20Sopenharmony_ci break; 1278c2ecf20Sopenharmony_ci case AF_INET6: 1288c2ecf20Sopenharmony_ci h ^= __xfrm6_addr_hash(daddr); 1298c2ecf20Sopenharmony_ci break; 1308c2ecf20Sopenharmony_ci } 1318c2ecf20Sopenharmony_ci return (h ^ (h >> 10) ^ (h >> 20)) & hmask; 1328c2ecf20Sopenharmony_ci} 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_cistatic inline unsigned int __idx_hash(u32 index, unsigned int hmask) 1358c2ecf20Sopenharmony_ci{ 1368c2ecf20Sopenharmony_ci return (index ^ (index >> 8)) & hmask; 1378c2ecf20Sopenharmony_ci} 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_cistatic inline unsigned int __sel_hash(const struct xfrm_selector *sel, 1408c2ecf20Sopenharmony_ci unsigned short family, unsigned int hmask, 1418c2ecf20Sopenharmony_ci u8 dbits, u8 sbits) 1428c2ecf20Sopenharmony_ci{ 1438c2ecf20Sopenharmony_ci const xfrm_address_t *daddr = &sel->daddr; 1448c2ecf20Sopenharmony_ci const xfrm_address_t *saddr = &sel->saddr; 1458c2ecf20Sopenharmony_ci unsigned int h = 0; 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci switch (family) { 1488c2ecf20Sopenharmony_ci case AF_INET: 1498c2ecf20Sopenharmony_ci if (sel->prefixlen_d < dbits || 1508c2ecf20Sopenharmony_ci sel->prefixlen_s < sbits) 1518c2ecf20Sopenharmony_ci return hmask + 1; 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci h = __xfrm4_dpref_spref_hash(daddr, saddr, dbits, sbits); 1548c2ecf20Sopenharmony_ci break; 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci case AF_INET6: 1578c2ecf20Sopenharmony_ci if (sel->prefixlen_d < dbits || 1588c2ecf20Sopenharmony_ci sel->prefixlen_s < sbits) 1598c2ecf20Sopenharmony_ci return hmask + 1; 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci h = __xfrm6_dpref_spref_hash(daddr, saddr, dbits, sbits); 1628c2ecf20Sopenharmony_ci break; 1638c2ecf20Sopenharmony_ci } 1648c2ecf20Sopenharmony_ci h ^= (h >> 16); 1658c2ecf20Sopenharmony_ci return h & hmask; 1668c2ecf20Sopenharmony_ci} 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_cistatic inline unsigned int __addr_hash(const xfrm_address_t *daddr, 1698c2ecf20Sopenharmony_ci const xfrm_address_t *saddr, 1708c2ecf20Sopenharmony_ci unsigned short family, 1718c2ecf20Sopenharmony_ci unsigned int hmask, 1728c2ecf20Sopenharmony_ci u8 dbits, u8 sbits) 1738c2ecf20Sopenharmony_ci{ 1748c2ecf20Sopenharmony_ci unsigned int h = 0; 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci switch (family) { 1778c2ecf20Sopenharmony_ci case AF_INET: 1788c2ecf20Sopenharmony_ci h = __xfrm4_dpref_spref_hash(daddr, saddr, dbits, sbits); 1798c2ecf20Sopenharmony_ci break; 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci case AF_INET6: 1828c2ecf20Sopenharmony_ci h = __xfrm6_dpref_spref_hash(daddr, saddr, dbits, sbits); 1838c2ecf20Sopenharmony_ci break; 1848c2ecf20Sopenharmony_ci } 1858c2ecf20Sopenharmony_ci h ^= (h >> 16); 1868c2ecf20Sopenharmony_ci return h & hmask; 1878c2ecf20Sopenharmony_ci} 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_cistruct hlist_head *xfrm_hash_alloc(unsigned int sz); 1908c2ecf20Sopenharmony_civoid xfrm_hash_free(struct hlist_head *n, unsigned int sz); 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci#endif /* _XFRM_HASH_H */ 193