allow coexistance of N build and AC build.
[tomato.git] / release / src-rt-6.x / linux / linux-2.6 / net / ipv4 / netfilter / ip_set_ipportnethash.c
blob2680cd9af837bdb85f509d98d12c3c3962d4d53f
1 /* Copyright (C) 2008 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 as
5 * published by the Free Software Foundation.
6 */
8 /* Kernel module implementing an ip+port+net hash set */
10 #include <linux/module.h>
11 #include <linux/moduleparam.h>
12 #include <linux/ip.h>
13 #include <linux/tcp.h>
14 #include <linux/udp.h>
15 #include <linux/skbuff.h>
16 #include <linux/netfilter_ipv4/ip_set_jhash.h>
17 #include <linux/errno.h>
18 #include <asm/uaccess.h>
19 #include <asm/bitops.h>
20 #include <linux/spinlock.h>
21 #include <linux/random.h>
23 #include <net/ip.h>
25 #include <linux/netfilter_ipv4/ip_set_ipportnethash.h>
26 #include <linux/netfilter_ipv4/ip_set_getport.h>
28 static int limit = MAX_RANGE;
30 #define jhash_ip2(map, i, ipport, ip1) \
31 jhash_2words(ipport, ip1, *(map->initval + i))
33 static inline __u32
34 ipportnethash_id_cidr(struct ip_set *set,
35 ip_set_ip_t ip, ip_set_ip_t port,
36 ip_set_ip_t ip1, uint8_t cidr)
38 struct ip_set_ipportnethash *map = set->data;
39 __u32 id;
40 u_int16_t i;
41 struct ipportip *elem;
43 ip = pack_ip_port(map, ip, port);
44 ip1 = pack_ip_cidr(ip1, cidr);
45 if (!(ip || ip1))
46 return UINT_MAX;
48 for (i = 0; i < map->probes; i++) {
49 id = jhash_ip2(map, i, ip, ip1) % map->hashsize;
50 DP("hash key: %u", id);
51 elem = HARRAY_ELEM(map->members, struct ipportip *, id);
52 if (elem->ip == ip && elem->ip1 == ip1)
53 return id;
54 /* No shortcut - there can be deleted entries. */
56 return UINT_MAX;
59 static inline __u32
60 ipportnethash_id(struct ip_set *set,
61 ip_set_ip_t ip, ip_set_ip_t port, ip_set_ip_t ip1)
63 struct ip_set_ipportnethash *map = set->data;
64 __u32 id = UINT_MAX;
65 int i;
67 for (i = 0; i < 30 && map->cidr[i]; i++) {
68 id = ipportnethash_id_cidr(set, ip, port, ip1, map->cidr[i]);
69 if (id != UINT_MAX)
70 break;
72 return id;
75 static inline int
76 ipportnethash_test_cidr(struct ip_set *set,
77 ip_set_ip_t ip, ip_set_ip_t port,
78 ip_set_ip_t ip1, uint8_t cidr)
80 struct ip_set_ipportnethash *map = set->data;
82 if (ip < map->first_ip || ip > map->last_ip)
83 return -ERANGE;
85 return (ipportnethash_id_cidr(set, ip, port, ip1, cidr) != UINT_MAX);
88 static inline int
89 ipportnethash_test(struct ip_set *set,
90 ip_set_ip_t ip, ip_set_ip_t port, ip_set_ip_t ip1)
92 struct ip_set_ipportnethash *map = set->data;
94 if (ip < map->first_ip || ip > map->last_ip)
95 return -ERANGE;
97 return (ipportnethash_id(set, ip, port, ip1) != UINT_MAX);
100 static int
101 ipportnethash_utest(struct ip_set *set, const void *data, u_int32_t size)
103 const struct ip_set_req_ipportnethash *req = data;
105 if (req->cidr <= 0 || req->cidr > 32)
106 return -EINVAL;
107 return (req->cidr == 32
108 ? ipportnethash_test(set, req->ip, req->port, req->ip1)
109 : ipportnethash_test_cidr(set, req->ip, req->port,
110 req->ip1, req->cidr));
113 #define KADT_CONDITION \
114 ip_set_ip_t port, ip1; \
116 if (flags[2] == 0) \
117 return 0; \
119 port = get_port(skb, ++flags); \
120 ip1 = ipaddr(skb, ++flags); \
122 if (port == INVALID_PORT) \
123 return 0;
125 KADT(ipportnethash, test, ipaddr, port, ip1)
127 static inline int
128 __ipportnet_add(struct ip_set_ipportnethash *map,
129 ip_set_ip_t ip, ip_set_ip_t ip1)
131 __u32 probe;
132 u_int16_t i;
133 struct ipportip *elem, *slot = NULL;
135 for (i = 0; i < map->probes; i++) {
136 probe = jhash_ip2(map, i, ip, ip1) % map->hashsize;
137 elem = HARRAY_ELEM(map->members, struct ipportip *, probe);
138 if (elem->ip == ip && elem->ip1 == ip1)
139 return -EEXIST;
140 if (!(slot || elem->ip || elem->ip1))
141 slot = elem;
142 /* There can be deleted entries, must check all slots */
144 if (slot) {
145 slot->ip = ip;
146 slot->ip1 = ip1;
147 map->elements++;
148 return 0;
150 /* Trigger rehashing */
151 return -EAGAIN;
154 static inline int
155 __ipportnethash_add(struct ip_set_ipportnethash *map,
156 struct ipportip *elem)
158 return __ipportnet_add(map, elem->ip, elem->ip1);
161 static inline int
162 ipportnethash_add(struct ip_set *set,
163 ip_set_ip_t ip, ip_set_ip_t port,
164 ip_set_ip_t ip1, uint8_t cidr)
166 struct ip_set_ipportnethash *map = set->data;
167 struct ipportip;
168 int ret;
170 if (map->elements > limit)
171 return -ERANGE;
172 if (ip < map->first_ip || ip > map->last_ip)
173 return -ERANGE;
174 if (cidr <= 0 || cidr >= 32)
175 return -EINVAL;
176 if (map->nets[cidr-1] == UINT16_MAX)
177 return -ERANGE;
179 ip = pack_ip_port(map, ip, port);
180 ip1 = pack_ip_cidr(ip1, cidr);
181 if (!(ip || ip1))
182 return -ERANGE;
184 ret =__ipportnet_add(map, ip, ip1);
185 if (ret == 0) {
186 if (!map->nets[cidr-1]++)
187 add_cidr_size(map->cidr, cidr);
189 return ret;
192 #undef KADT_CONDITION
193 #define KADT_CONDITION \
194 struct ip_set_ipportnethash *map = set->data; \
195 uint8_t cidr = map->cidr[0] ? map->cidr[0] : 31; \
196 ip_set_ip_t port, ip1; \
198 if (flags[2] == 0) \
199 return 0; \
201 port = get_port(skb, flags++); \
202 ip1 = ipaddr(skb, flags++); \
204 if (port == INVALID_PORT) \
205 return 0;
207 UADT(ipportnethash, add, req->port, req->ip1, req->cidr)
208 KADT(ipportnethash, add, ipaddr, port, ip1, cidr)
210 static inline void
211 __ipportnethash_retry(struct ip_set_ipportnethash *tmp,
212 struct ip_set_ipportnethash *map)
214 tmp->first_ip = map->first_ip;
215 tmp->last_ip = map->last_ip;
216 memcpy(tmp->cidr, map->cidr, sizeof(tmp->cidr));
217 memcpy(tmp->nets, map->nets, sizeof(tmp->nets));
220 HASH_RETRY2(ipportnethash, struct ipportip)
222 static inline int
223 ipportnethash_del(struct ip_set *set,
224 ip_set_ip_t ip, ip_set_ip_t port,
225 ip_set_ip_t ip1, uint8_t cidr)
227 struct ip_set_ipportnethash *map = set->data;
228 ip_set_ip_t id;
229 struct ipportip *elem;
231 if (ip < map->first_ip || ip > map->last_ip)
232 return -ERANGE;
233 if (!ip)
234 return -ERANGE;
235 if (cidr <= 0 || cidr >= 32)
236 return -EINVAL;
238 id = ipportnethash_id_cidr(set, ip, port, ip1, cidr);
240 if (id == UINT_MAX)
241 return -EEXIST;
243 elem = HARRAY_ELEM(map->members, struct ipportip *, id);
244 elem->ip = elem->ip1 = 0;
245 map->elements--;
246 if (!map->nets[cidr-1]--)
247 del_cidr_size(map->cidr, cidr);
249 return 0;
252 UADT(ipportnethash, del, req->port, req->ip1, req->cidr)
253 KADT(ipportnethash, del, ipaddr, port, ip1, cidr)
255 static inline int
256 __ipportnethash_create(const struct ip_set_req_ipportnethash_create *req,
257 struct ip_set_ipportnethash *map)
259 if (req->to - req->from > MAX_RANGE) {
260 ip_set_printk("range too big, %d elements (max %d)",
261 req->to - req->from + 1, MAX_RANGE+1);
262 return -ENOEXEC;
264 map->first_ip = req->from;
265 map->last_ip = req->to;
266 memset(map->cidr, 0, sizeof(map->cidr));
267 memset(map->nets, 0, sizeof(map->nets));
268 return 0;
271 HASH_CREATE(ipportnethash, struct ipportip)
272 HASH_DESTROY(ipportnethash)
273 HASH_FLUSH_CIDR(ipportnethash, struct ipportip);
275 static inline void
276 __ipportnethash_list_header(const struct ip_set_ipportnethash *map,
277 struct ip_set_req_ipportnethash_create *header)
279 header->from = map->first_ip;
280 header->to = map->last_ip;
283 HASH_LIST_HEADER(ipportnethash)
285 HASH_LIST_MEMBERS_SIZE(ipportnethash, struct ipportip)
286 HASH_LIST_MEMBERS_MEMCPY(ipportnethash, struct ipportip,
287 (elem->ip || elem->ip1))
289 IP_SET_RTYPE(ipportnethash, IPSET_TYPE_IP | IPSET_TYPE_PORT
290 | IPSET_TYPE_IP1 | IPSET_DATA_TRIPLE)
292 MODULE_LICENSE("GPL");
293 MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
294 MODULE_DESCRIPTION("ipportnethash type of IP sets");
295 module_param(limit, int, 0600);
296 MODULE_PARM_DESC(limit, "maximal number of elements stored in the sets");
298 REGISTER_MODULE(ipportnethash)