1#ifndef _XFRM_HASH_H
2#define _XFRM_HASH_H
3
4#include <linux/xfrm.h>
5#include <linux/socket.h>
6
7static inline unsigned int __xfrm4_addr_hash(const xfrm_address_t *addr)
8{
9	return ntohl(addr->a4);
10}
11
12static inline unsigned int __xfrm6_addr_hash(const xfrm_address_t *addr)
13{
14	return ntohl(addr->a6[2] ^ addr->a6[3]);
15}
16
17static inline unsigned int __xfrm4_daddr_saddr_hash(const xfrm_address_t *daddr,
18						    const xfrm_address_t *saddr)
19{
20	u32 sum = (__force u32)daddr->a4 + (__force u32)saddr->a4;
21	return ntohl((__force __be32)sum);
22}
23
24static inline unsigned int __xfrm6_daddr_saddr_hash(const xfrm_address_t *daddr,
25						    const xfrm_address_t *saddr)
26{
27	return ntohl(daddr->a6[2] ^ daddr->a6[3] ^
28		     saddr->a6[2] ^ saddr->a6[3]);
29}
30
31static inline unsigned int __xfrm_dst_hash(const xfrm_address_t *daddr,
32					   const xfrm_address_t *saddr,
33					   u32 reqid, unsigned short family,
34					   unsigned int hmask)
35{
36	unsigned int h = family ^ reqid;
37	switch (family) {
38	case AF_INET:
39		h ^= __xfrm4_daddr_saddr_hash(daddr, saddr);
40		break;
41	case AF_INET6:
42		h ^= __xfrm6_daddr_saddr_hash(daddr, saddr);
43		break;
44	}
45	return (h ^ (h >> 16)) & hmask;
46}
47
48static inline unsigned int __xfrm_src_hash(const xfrm_address_t *daddr,
49					   const xfrm_address_t *saddr,
50					   unsigned short family,
51					   unsigned int hmask)
52{
53	unsigned int h = family;
54	switch (family) {
55	case AF_INET:
56		h ^= __xfrm4_daddr_saddr_hash(daddr, saddr);
57		break;
58	case AF_INET6:
59		h ^= __xfrm6_daddr_saddr_hash(daddr, saddr);
60		break;
61	}
62	return (h ^ (h >> 16)) & hmask;
63}
64
65static inline unsigned int
66__xfrm_spi_hash(const xfrm_address_t *daddr, __be32 spi, u8 proto,
67		unsigned short family, unsigned int hmask)
68{
69	unsigned int h = (__force u32)spi ^ proto;
70	switch (family) {
71	case AF_INET:
72		h ^= __xfrm4_addr_hash(daddr);
73		break;
74	case AF_INET6:
75		h ^= __xfrm6_addr_hash(daddr);
76		break;
77	}
78	return (h ^ (h >> 10) ^ (h >> 20)) & hmask;
79}
80
81static inline unsigned int __idx_hash(u32 index, unsigned int hmask)
82{
83	return (index ^ (index >> 8)) & hmask;
84}
85
86static inline unsigned int __sel_hash(const struct xfrm_selector *sel,
87				      unsigned short family, unsigned int hmask)
88{
89	const xfrm_address_t *daddr = &sel->daddr;
90	const xfrm_address_t *saddr = &sel->saddr;
91	unsigned int h = 0;
92
93	switch (family) {
94	case AF_INET:
95		if (sel->prefixlen_d != 32 ||
96		    sel->prefixlen_s != 32)
97			return hmask + 1;
98
99		h = __xfrm4_daddr_saddr_hash(daddr, saddr);
100		break;
101
102	case AF_INET6:
103		if (sel->prefixlen_d != 128 ||
104		    sel->prefixlen_s != 128)
105			return hmask + 1;
106
107		h = __xfrm6_daddr_saddr_hash(daddr, saddr);
108		break;
109	}
110	h ^= (h >> 16);
111	return h & hmask;
112}
113
114static inline unsigned int __addr_hash(const xfrm_address_t *daddr,
115				       const xfrm_address_t *saddr,
116				       unsigned short family, unsigned int hmask)
117{
118	unsigned int h = 0;
119
120	switch (family) {
121	case AF_INET:
122		h = __xfrm4_daddr_saddr_hash(daddr, saddr);
123		break;
124
125	case AF_INET6:
126		h = __xfrm6_daddr_saddr_hash(daddr, saddr);
127		break;
128	}
129	h ^= (h >> 16);
130	return h & hmask;
131}
132
133extern struct hlist_head *xfrm_hash_alloc(unsigned int sz);
134extern void xfrm_hash_free(struct hlist_head *n, unsigned int sz);
135
136#endif /* _XFRM_HASH_H */
137