]> git.pld-linux.org Git - packages/kernel.git/blame - kernel-pom-ng-set.patch
- up to 2.6.25.12
[packages/kernel.git] / kernel-pom-ng-set.patch
CommitLineData
7d2f026e 1diff -uNrp --exclude=.svn a/include/linux/netfilter_ipv4/ip_set.h linux-2.6/include/linux/netfilter_ipv4/ip_set.h
2--- a/include/linux/netfilter_ipv4/ip_set.h 1970-01-01 01:00:00.000000000 +0100
3+++ linux-2.6/include/linux/netfilter_ipv4/ip_set.h 2008-07-08 16:52:53.465235839 +0200
1aedc22c 4@@ -0,0 +1,498 @@
5+#ifndef _IP_SET_H
6+#define _IP_SET_H
7+
8+/* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu>
9+ * Patrick Schaaf <bof@bof.de>
10+ * Martin Josefsson <gandalf@wlug.westbo.se>
11+ * Copyright (C) 2003-2004 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
12+ *
13+ * This program is free software; you can redistribute it and/or modify
14+ * it under the terms of the GNU General Public License version 2 as
15+ * published by the Free Software Foundation.
16+ */
17+
18+#if 0
19+#define IP_SET_DEBUG
20+#endif
21+
22+/*
23+ * A sockopt of such quality has hardly ever been seen before on the open
24+ * market! This little beauty, hardly ever used: above 64, so it's
25+ * traditionally used for firewalling, not touched (even once!) by the
26+ * 2.0, 2.2 and 2.4 kernels!
27+ *
28+ * Comes with its own certificate of authenticity, valid anywhere in the
29+ * Free world!
30+ *
31+ * Rusty, 19.4.2000
32+ */
33+#define SO_IP_SET 83
34+
35+/*
36+ * Heavily modify by Joakim Axelsson 08.03.2002
37+ * - Made it more modulebased
38+ *
39+ * Additional heavy modifications by Jozsef Kadlecsik 22.02.2004
40+ * - bindings added
41+ * - in order to "deal with" backward compatibility, renamed to ipset
42+ */
43+
44+/*
45+ * Used so that the kernel module and ipset-binary can match their versions
46+ */
47+#define IP_SET_PROTOCOL_VERSION 2
48+
49+#define IP_SET_MAXNAMELEN 32 /* set names and set typenames */
50+
51+/* Lets work with our own typedef for representing an IP address.
52+ * We hope to make the code more portable, possibly to IPv6...
53+ *
54+ * The representation works in HOST byte order, because most set types
55+ * will perform arithmetic operations and compare operations.
56+ *
57+ * For now the type is an uint32_t.
58+ *
59+ * Make sure to ONLY use the functions when translating and parsing
60+ * in order to keep the host byte order and make it more portable:
61+ * parse_ip()
62+ * parse_mask()
63+ * parse_ipandmask()
64+ * ip_tostring()
65+ * (Joakim: where are they???)
66+ */
67+
68+typedef uint32_t ip_set_ip_t;
69+
70+/* Sets are identified by an id in kernel space. Tweak with ip_set_id_t
71+ * and IP_SET_INVALID_ID if you want to increase the max number of sets.
72+ */
73+typedef uint16_t ip_set_id_t;
74+
75+#define IP_SET_INVALID_ID 65535
76+
77+/* How deep we follow bindings */
78+#define IP_SET_MAX_BINDINGS 6
79+
80+/*
81+ * Option flags for kernel operations (ipt_set_info)
82+ */
83+#define IPSET_SRC 0x01 /* Source match/add */
84+#define IPSET_DST 0x02 /* Destination match/add */
85+#define IPSET_MATCH_INV 0x04 /* Inverse matching */
86+
87+/*
88+ * Set features
89+ */
90+#define IPSET_TYPE_IP 0x01 /* IP address type of set */
91+#define IPSET_TYPE_PORT 0x02 /* Port type of set */
92+#define IPSET_DATA_SINGLE 0x04 /* Single data storage */
93+#define IPSET_DATA_DOUBLE 0x08 /* Double data storage */
94+
95+/* Reserved keywords */
96+#define IPSET_TOKEN_DEFAULT ":default:"
97+#define IPSET_TOKEN_ALL ":all:"
98+
99+/* SO_IP_SET operation constants, and their request struct types.
100+ *
101+ * Operation ids:
102+ * 0-99: commands with version checking
103+ * 100-199: add/del/test/bind/unbind
104+ * 200-299: list, save, restore
105+ */
106+
107+/* Single shot operations:
108+ * version, create, destroy, flush, rename and swap
109+ *
110+ * Sets are identified by name.
111+ */
112+
113+#define IP_SET_REQ_STD \
114+ unsigned op; \
115+ unsigned version; \
116+ char name[IP_SET_MAXNAMELEN]
117+
118+#define IP_SET_OP_CREATE 0x00000001 /* Create a new (empty) set */
119+struct ip_set_req_create {
120+ IP_SET_REQ_STD;
121+ char typename[IP_SET_MAXNAMELEN];
122+};
123+
124+#define IP_SET_OP_DESTROY 0x00000002 /* Remove a (empty) set */
125+struct ip_set_req_std {
126+ IP_SET_REQ_STD;
127+};
128+
129+#define IP_SET_OP_FLUSH 0x00000003 /* Remove all IPs in a set */
130+/* Uses ip_set_req_std */
131+
132+#define IP_SET_OP_RENAME 0x00000004 /* Rename a set */
133+/* Uses ip_set_req_create */
134+
135+#define IP_SET_OP_SWAP 0x00000005 /* Swap two sets */
136+/* Uses ip_set_req_create */
137+
138+union ip_set_name_index {
139+ char name[IP_SET_MAXNAMELEN];
140+ ip_set_id_t index;
141+};
142+
143+#define IP_SET_OP_GET_BYNAME 0x00000006 /* Get set index by name */
144+struct ip_set_req_get_set {
145+ unsigned op;
146+ unsigned version;
147+ union ip_set_name_index set;
148+};
149+
150+#define IP_SET_OP_GET_BYINDEX 0x00000007 /* Get set name by index */
151+/* Uses ip_set_req_get_set */
152+
153+#define IP_SET_OP_VERSION 0x00000100 /* Ask kernel version */
154+struct ip_set_req_version {
155+ unsigned op;
156+ unsigned version;
157+};
158+
159+/* Double shots operations:
160+ * add, del, test, bind and unbind.
161+ *
162+ * First we query the kernel to get the index and type of the target set,
163+ * then issue the command. Validity of IP is checked in kernel in order
164+ * to minimalize sockopt operations.
165+ */
166+
167+/* Get minimal set data for add/del/test/bind/unbind IP */
168+#define IP_SET_OP_ADT_GET 0x00000010 /* Get set and type */
169+struct ip_set_req_adt_get {
170+ unsigned op;
171+ unsigned version;
172+ union ip_set_name_index set;
173+ char typename[IP_SET_MAXNAMELEN];
174+};
175+
176+#define IP_SET_REQ_BYINDEX \
177+ unsigned op; \
178+ ip_set_id_t index;
179+
180+struct ip_set_req_adt {
181+ IP_SET_REQ_BYINDEX;
182+};
183+
184+#define IP_SET_OP_ADD_IP 0x00000101 /* Add an IP to a set */
185+/* Uses ip_set_req_adt, with type specific addage */
186+
187+#define IP_SET_OP_DEL_IP 0x00000102 /* Remove an IP from a set */
188+/* Uses ip_set_req_adt, with type specific addage */
189+
190+#define IP_SET_OP_TEST_IP 0x00000103 /* Test an IP in a set */
191+/* Uses ip_set_req_adt, with type specific addage */
192+
193+#define IP_SET_OP_BIND_SET 0x00000104 /* Bind an IP to a set */
194+/* Uses ip_set_req_bind, with type specific addage */
195+struct ip_set_req_bind {
196+ IP_SET_REQ_BYINDEX;
197+ char binding[IP_SET_MAXNAMELEN];
198+};
199+
200+#define IP_SET_OP_UNBIND_SET 0x00000105 /* Unbind an IP from a set */
201+/* Uses ip_set_req_bind, with type speficic addage
202+ * index = 0 means unbinding for all sets */
203+
204+#define IP_SET_OP_TEST_BIND_SET 0x00000106 /* Test binding an IP to a set */
205+/* Uses ip_set_req_bind, with type specific addage */
206+
207+/* Multiple shots operations: list, save, restore.
208+ *
209+ * - check kernel version and query the max number of sets
210+ * - get the basic information on all sets
211+ * and size required for the next step
212+ * - get actual set data: header, data, bindings
213+ */
214+
215+/* Get max_sets and the index of a queried set
216+ */
217+#define IP_SET_OP_MAX_SETS 0x00000020
218+struct ip_set_req_max_sets {
219+ unsigned op;
220+ unsigned version;
221+ ip_set_id_t max_sets; /* max_sets */
222+ ip_set_id_t sets; /* real number of sets */
223+ union ip_set_name_index set; /* index of set if name used */
224+};
225+
226+/* Get the id and name of the sets plus size for next step */
227+#define IP_SET_OP_LIST_SIZE 0x00000201
228+#define IP_SET_OP_SAVE_SIZE 0x00000202
229+struct ip_set_req_setnames {
230+ unsigned op;
231+ ip_set_id_t index; /* set to list/save */
232+ size_t size; /* size to get setdata/bindings */
233+ /* followed by sets number of struct ip_set_name_list */
234+};
235+
236+struct ip_set_name_list {
237+ char name[IP_SET_MAXNAMELEN];
238+ char typename[IP_SET_MAXNAMELEN];
239+ ip_set_id_t index;
240+ ip_set_id_t id;
241+};
242+
243+/* The actual list operation */
244+#define IP_SET_OP_LIST 0x00000203
245+struct ip_set_req_list {
246+ IP_SET_REQ_BYINDEX;
247+ /* sets number of struct ip_set_list in reply */
248+};
249+
250+struct ip_set_list {
251+ ip_set_id_t index;
252+ ip_set_id_t binding;
253+ u_int32_t ref;
254+ size_t header_size; /* Set header data of header_size */
255+ size_t members_size; /* Set members data of members_size */
256+ size_t bindings_size; /* Set bindings data of bindings_size */
257+};
258+
259+struct ip_set_hash_list {
260+ ip_set_ip_t ip;
261+ ip_set_id_t binding;
262+};
263+
264+/* The save operation */
265+#define IP_SET_OP_SAVE 0x00000204
266+/* Uses ip_set_req_list, in the reply replaced by
267+ * sets number of struct ip_set_save plus a marker
268+ * ip_set_save followed by ip_set_hash_save structures.
269+ */
270+struct ip_set_save {
271+ ip_set_id_t index;
272+ ip_set_id_t binding;
273+ size_t header_size; /* Set header data of header_size */
274+ size_t members_size; /* Set members data of members_size */
275+};
276+
277+/* At restoring, ip == 0 means default binding for the given set: */
278+struct ip_set_hash_save {
279+ ip_set_ip_t ip;
280+ ip_set_id_t id;
281+ ip_set_id_t binding;
282+};
283+
284+/* The restore operation */
285+#define IP_SET_OP_RESTORE 0x00000205
286+/* Uses ip_set_req_setnames followed by ip_set_restore structures
287+ * plus a marker ip_set_restore, followed by ip_set_hash_save
288+ * structures.
289+ */
290+struct ip_set_restore {
291+ char name[IP_SET_MAXNAMELEN];
292+ char typename[IP_SET_MAXNAMELEN];
293+ ip_set_id_t index;
294+ size_t header_size; /* Create data of header_size */
295+ size_t members_size; /* Set members data of members_size */
296+};
297+
298+static inline int bitmap_bytes(ip_set_ip_t a, ip_set_ip_t b)
299+{
300+ return 4 * ((((b - a + 8) / 8) + 3) / 4);
301+}
302+
303+#ifdef __KERNEL__
304+
305+#define ip_set_printk(format, args...) \
306+ do { \
307+ printk("%s: %s: ", __FILE__, __FUNCTION__); \
308+ printk(format "\n" , ## args); \
309+ } while (0)
310+
311+#if defined(IP_SET_DEBUG)
312+#define DP(format, args...) \
313+ do { \
314+ printk("%s: %s (DBG): ", __FILE__, __FUNCTION__);\
315+ printk(format "\n" , ## args); \
316+ } while (0)
317+#define IP_SET_ASSERT(x) \
318+ do { \
319+ if (!(x)) \
320+ printk("IP_SET_ASSERT: %s:%i(%s)\n", \
321+ __FILE__, __LINE__, __FUNCTION__); \
322+ } while (0)
323+#else
324+#define DP(format, args...)
325+#define IP_SET_ASSERT(x)
326+#endif
327+
328+struct ip_set;
329+
330+/*
331+ * The ip_set_type definition - one per set type, e.g. "ipmap".
332+ *
333+ * Each individual set has a pointer, set->type, going to one
334+ * of these structures. Function pointers inside the structure implement
335+ * the real behaviour of the sets.
336+ *
337+ * If not mentioned differently, the implementation behind the function
338+ * pointers of a set_type, is expected to return 0 if ok, and a negative
339+ * errno (e.g. -EINVAL) on error.
340+ */
341+struct ip_set_type {
342+ struct list_head list; /* next in list of set types */
343+
344+ /* test for IP in set (kernel: iptables -m set src|dst)
345+ * return 0 if not in set, 1 if in set.
346+ */
347+ int (*testip_kernel) (struct ip_set *set,
348+ const struct sk_buff * skb,
349+ ip_set_ip_t *ip,
350+ const u_int32_t *flags,
351+ unsigned char index);
352+
353+ /* test for IP in set (userspace: ipset -T set IP)
354+ * return 0 if not in set, 1 if in set.
355+ */
356+ int (*testip) (struct ip_set *set,
357+ const void *data, size_t size,
358+ ip_set_ip_t *ip);
359+
360+ /*
361+ * Size of the data structure passed by when
362+ * adding/deletin/testing an entry.
363+ */
364+ size_t reqsize;
365+
366+ /* Add IP into set (userspace: ipset -A set IP)
367+ * Return -EEXIST if the address is already in the set,
368+ * and -ERANGE if the address lies outside the set bounds.
369+ * If the address was not already in the set, 0 is returned.
370+ */
371+ int (*addip) (struct ip_set *set,
372+ const void *data, size_t size,
373+ ip_set_ip_t *ip);
374+
375+ /* Add IP into set (kernel: iptables ... -j SET set src|dst)
376+ * Return -EEXIST if the address is already in the set,
377+ * and -ERANGE if the address lies outside the set bounds.
378+ * If the address was not already in the set, 0 is returned.
379+ */
380+ int (*addip_kernel) (struct ip_set *set,
381+ const struct sk_buff * skb,
382+ ip_set_ip_t *ip,
383+ const u_int32_t *flags,
384+ unsigned char index);
385+
386+ /* remove IP from set (userspace: ipset -D set --entry x)
387+ * Return -EEXIST if the address is NOT in the set,
388+ * and -ERANGE if the address lies outside the set bounds.
389+ * If the address really was in the set, 0 is returned.
390+ */
391+ int (*delip) (struct ip_set *set,
392+ const void *data, size_t size,
393+ ip_set_ip_t *ip);
394+
395+ /* remove IP from set (kernel: iptables ... -j SET --entry x)
396+ * Return -EEXIST if the address is NOT in the set,
397+ * and -ERANGE if the address lies outside the set bounds.
398+ * If the address really was in the set, 0 is returned.
399+ */
400+ int (*delip_kernel) (struct ip_set *set,
401+ const struct sk_buff * skb,
402+ ip_set_ip_t *ip,
403+ const u_int32_t *flags,
404+ unsigned char index);
405+
406+ /* new set creation - allocated type specific items
407+ */
408+ int (*create) (struct ip_set *set,
409+ const void *data, size_t size);
410+
411+ /* retry the operation after successfully tweaking the set
412+ */
413+ int (*retry) (struct ip_set *set);
414+
415+ /* set destruction - free type specific items
416+ * There is no return value.
417+ * Can be called only when child sets are destroyed.
418+ */
419+ void (*destroy) (struct ip_set *set);
420+
421+ /* set flushing - reset all bits in the set, or something similar.
422+ * There is no return value.
423+ */
424+ void (*flush) (struct ip_set *set);
425+
426+ /* Listing: size needed for header
427+ */
428+ size_t header_size;
429+
430+ /* Listing: Get the header
431+ *
432+ * Fill in the information in "data".
433+ * This function is always run after list_header_size() under a
434+ * writelock on the set. Therefor is the length of "data" always
435+ * correct.
436+ */
437+ void (*list_header) (const struct ip_set *set,
438+ void *data);
439+
440+ /* Listing: Get the size for the set members
441+ */
442+ int (*list_members_size) (const struct ip_set *set);
443+
444+ /* Listing: Get the set members
445+ *
446+ * Fill in the information in "data".
447+ * This function is always run after list_member_size() under a
448+ * writelock on the set. Therefor is the length of "data" always
449+ * correct.
450+ */
451+ void (*list_members) (const struct ip_set *set,
452+ void *data);
453+
454+ char typename[IP_SET_MAXNAMELEN];
455+ unsigned char features;
456+ int protocol_version;
457+
458+ /* Set this to THIS_MODULE if you are a module, otherwise NULL */
459+ struct module *me;
460+};
461+
462+extern int ip_set_register_set_type(struct ip_set_type *set_type);
463+extern void ip_set_unregister_set_type(struct ip_set_type *set_type);
464+
465+/* A generic ipset */
466+struct ip_set {
467+ char name[IP_SET_MAXNAMELEN]; /* the name of the set */
468+ rwlock_t lock; /* lock for concurrency control */
469+ ip_set_id_t id; /* set id for swapping */
470+ ip_set_id_t binding; /* default binding for the set */
471+ atomic_t ref; /* in kernel and in hash references */
472+ struct ip_set_type *type; /* the set types */
473+ void *data; /* pooltype specific data */
474+};
475+
476+/* Structure to bind set elements to sets */
477+struct ip_set_hash {
478+ struct list_head list; /* list of clashing entries in hash */
479+ ip_set_ip_t ip; /* ip from set */
480+ ip_set_id_t id; /* set id */
481+ ip_set_id_t binding; /* set we bind the element to */
482+};
483+
484+/* register and unregister set references */
485+extern ip_set_id_t ip_set_get_byname(const char name[IP_SET_MAXNAMELEN]);
486+extern ip_set_id_t ip_set_get_byindex(ip_set_id_t id);
487+extern void ip_set_put(ip_set_id_t id);
488+
489+/* API for iptables set match, and SET target */
490+extern void ip_set_addip_kernel(ip_set_id_t id,
491+ const struct sk_buff *skb,
492+ const u_int32_t *flags);
493+extern void ip_set_delip_kernel(ip_set_id_t id,
494+ const struct sk_buff *skb,
495+ const u_int32_t *flags);
496+extern int ip_set_testip_kernel(ip_set_id_t id,
497+ const struct sk_buff *skb,
498+ const u_int32_t *flags);
499+
500+#endif /* __KERNEL__ */
501+
502+#endif /*_IP_SET_H*/
7d2f026e 503diff -uNrp --exclude=.svn a/include/linux/netfilter_ipv4/ip_set_iphash.h linux-2.6/include/linux/netfilter_ipv4/ip_set_iphash.h
504--- a/include/linux/netfilter_ipv4/ip_set_iphash.h 1970-01-01 01:00:00.000000000 +0100
505+++ linux-2.6/include/linux/netfilter_ipv4/ip_set_iphash.h 2008-07-08 16:52:53.465235839 +0200
1aedc22c 506@@ -0,0 +1,30 @@
507+#ifndef __IP_SET_IPHASH_H
508+#define __IP_SET_IPHASH_H
509+
510+#include <linux/netfilter_ipv4/ip_set.h>
511+
512+#define SETTYPE_NAME "iphash"
513+#define MAX_RANGE 0x0000FFFF
514+
515+struct ip_set_iphash {
516+ ip_set_ip_t *members; /* the iphash proper */
517+ uint32_t elements; /* number of elements */
518+ uint32_t hashsize; /* hash size */
519+ uint16_t probes; /* max number of probes */
520+ uint16_t resize; /* resize factor in percent */
521+ ip_set_ip_t netmask; /* netmask */
522+ void *initval[0]; /* initvals for jhash_1word */
523+};
524+
525+struct ip_set_req_iphash_create {
526+ uint32_t hashsize;
527+ uint16_t probes;
528+ uint16_t resize;
529+ ip_set_ip_t netmask;
530+};
531+
532+struct ip_set_req_iphash {
533+ ip_set_ip_t ip;
534+};
535+
536+#endif /* __IP_SET_IPHASH_H */
7d2f026e 537diff -uNrp --exclude=.svn a/include/linux/netfilter_ipv4/ip_set_ipmap.h linux-2.6/include/linux/netfilter_ipv4/ip_set_ipmap.h
538--- a/include/linux/netfilter_ipv4/ip_set_ipmap.h 1970-01-01 01:00:00.000000000 +0100
539+++ linux-2.6/include/linux/netfilter_ipv4/ip_set_ipmap.h 2008-07-08 16:52:53.465235839 +0200
1aedc22c 540@@ -0,0 +1,56 @@
541+#ifndef __IP_SET_IPMAP_H
542+#define __IP_SET_IPMAP_H
543+
544+#include <linux/netfilter_ipv4/ip_set.h>
545+
546+#define SETTYPE_NAME "ipmap"
547+#define MAX_RANGE 0x0000FFFF
548+
549+struct ip_set_ipmap {
550+ void *members; /* the ipmap proper */
551+ ip_set_ip_t first_ip; /* host byte order, included in range */
552+ ip_set_ip_t last_ip; /* host byte order, included in range */
553+ ip_set_ip_t netmask; /* subnet netmask */
554+ ip_set_ip_t sizeid; /* size of set in IPs */
555+ ip_set_ip_t hosts; /* number of hosts in a subnet */
556+};
557+
558+struct ip_set_req_ipmap_create {
559+ ip_set_ip_t from;
560+ ip_set_ip_t to;
561+ ip_set_ip_t netmask;
562+};
563+
564+struct ip_set_req_ipmap {
565+ ip_set_ip_t ip;
566+};
567+
568+unsigned int
569+mask_to_bits(ip_set_ip_t mask)
570+{
571+ unsigned int bits = 32;
572+ ip_set_ip_t maskaddr;
573+
574+ if (mask == 0xFFFFFFFF)
575+ return bits;
576+
577+ maskaddr = 0xFFFFFFFE;
578+ while (--bits >= 0 && maskaddr != mask)
579+ maskaddr <<= 1;
580+
581+ return bits;
582+}
583+
584+ip_set_ip_t
585+range_to_mask(ip_set_ip_t from, ip_set_ip_t to, unsigned int *bits)
586+{
587+ ip_set_ip_t mask = 0xFFFFFFFE;
588+
589+ *bits = 32;
590+ while (--(*bits) >= 0 && mask && (to & mask) != from)
591+ mask <<= 1;
592+
593+ return mask;
594+}
595+
596+#endif /* __IP_SET_IPMAP_H */
7d2f026e 597diff -uNrp --exclude=.svn a/include/linux/netfilter_ipv4/ip_set_ipporthash.h linux-2.6/include/linux/netfilter_ipv4/ip_set_ipporthash.h
598--- a/include/linux/netfilter_ipv4/ip_set_ipporthash.h 1970-01-01 01:00:00.000000000 +0100
599+++ linux-2.6/include/linux/netfilter_ipv4/ip_set_ipporthash.h 2008-07-08 16:52:53.465235839 +0200
1aedc22c 600@@ -0,0 +1,34 @@
601+#ifndef __IP_SET_IPPORTHASH_H
602+#define __IP_SET_IPPORTHASH_H
603+
604+#include <linux/netfilter_ipv4/ip_set.h>
605+
606+#define SETTYPE_NAME "ipporthash"
607+#define MAX_RANGE 0x0000FFFF
608+#define INVALID_PORT (MAX_RANGE + 1)
609+
610+struct ip_set_ipporthash {
611+ ip_set_ip_t *members; /* the ipporthash proper */
612+ uint32_t elements; /* number of elements */
613+ uint32_t hashsize; /* hash size */
614+ uint16_t probes; /* max number of probes */
615+ uint16_t resize; /* resize factor in percent */
616+ ip_set_ip_t first_ip; /* host byte order, included in range */
617+ ip_set_ip_t last_ip; /* host byte order, included in range */
618+ void *initval[0]; /* initvals for jhash_1word */
619+};
620+
621+struct ip_set_req_ipporthash_create {
622+ uint32_t hashsize;
623+ uint16_t probes;
624+ uint16_t resize;
625+ ip_set_ip_t from;
626+ ip_set_ip_t to;
627+};
628+
629+struct ip_set_req_ipporthash {
630+ ip_set_ip_t ip;
631+ ip_set_ip_t port;
632+};
633+
634+#endif /* __IP_SET_IPPORTHASH_H */
7d2f026e 635diff -uNrp --exclude=.svn a/include/linux/netfilter_ipv4/ip_set_iptree.h linux-2.6/include/linux/netfilter_ipv4/ip_set_iptree.h
636--- a/include/linux/netfilter_ipv4/ip_set_iptree.h 1970-01-01 01:00:00.000000000 +0100
637+++ linux-2.6/include/linux/netfilter_ipv4/ip_set_iptree.h 2008-07-08 16:52:53.465235839 +0200
1aedc22c 638@@ -0,0 +1,40 @@
639+#ifndef __IP_SET_IPTREE_H
640+#define __IP_SET_IPTREE_H
641+
642+#include <linux/netfilter_ipv4/ip_set.h>
643+
644+#define SETTYPE_NAME "iptree"
645+#define MAX_RANGE 0x0000FFFF
646+
647+struct ip_set_iptreed {
648+ unsigned long expires[256]; /* x.x.x.ADDR */
649+};
650+
651+struct ip_set_iptreec {
652+ struct ip_set_iptreed *tree[256]; /* x.x.ADDR.* */
653+};
654+
655+struct ip_set_iptreeb {
656+ struct ip_set_iptreec *tree[256]; /* x.ADDR.*.* */
657+};
658+
659+struct ip_set_iptree {
660+ unsigned int timeout;
661+ unsigned int gc_interval;
662+#ifdef __KERNEL__
663+ uint32_t elements; /* number of elements */
664+ struct timer_list gc;
665+ struct ip_set_iptreeb *tree[256]; /* ADDR.*.*.* */
666+#endif
667+};
668+
669+struct ip_set_req_iptree_create {
670+ unsigned int timeout;
671+};
672+
673+struct ip_set_req_iptree {
674+ ip_set_ip_t ip;
675+ unsigned int timeout;
676+};
677+
678+#endif /* __IP_SET_IPTREE_H */
7d2f026e 679diff -uNrp --exclude=.svn a/include/linux/netfilter_ipv4/ip_set_iptreemap.h linux-2.6/include/linux/netfilter_ipv4/ip_set_iptreemap.h
680--- a/include/linux/netfilter_ipv4/ip_set_iptreemap.h 1970-01-01 01:00:00.000000000 +0100
681+++ linux-2.6/include/linux/netfilter_ipv4/ip_set_iptreemap.h 2008-07-08 16:52:53.465235839 +0200
f45e9687 682@@ -0,0 +1,40 @@
683+#ifndef __IP_SET_IPTREEMAP_H
684+#define __IP_SET_IPTREEMAP_H
685+
686+#include <linux/netfilter_ipv4/ip_set.h>
687+
688+#define SETTYPE_NAME "iptreemap"
689+
690+#ifdef __KERNEL__
691+struct ip_set_iptreemap_d {
692+ unsigned char bitmap[32]; /* x.x.x.y */
693+};
694+
695+struct ip_set_iptreemap_c {
696+ struct ip_set_iptreemap_d *tree[256]; /* x.x.y.x */
697+};
698+
699+struct ip_set_iptreemap_b {
700+ struct ip_set_iptreemap_c *tree[256]; /* x.y.x.x */
701+ unsigned char dirty[32];
702+};
703+#endif
704+
705+struct ip_set_iptreemap {
706+ unsigned int gc_interval;
707+#ifdef __KERNEL__
708+ struct timer_list gc;
709+ struct ip_set_iptreemap_b *tree[256]; /* y.x.x.x */
710+#endif
711+};
712+
713+struct ip_set_req_iptreemap_create {
714+ unsigned int gc_interval;
715+};
716+
717+struct ip_set_req_iptreemap {
718+ ip_set_ip_t start;
719+ ip_set_ip_t end;
720+};
721+
722+#endif /* __IP_SET_IPTREEMAP_H */
7d2f026e 723diff -uNrp --exclude=.svn a/include/linux/netfilter_ipv4/ip_set_jhash.h linux-2.6/include/linux/netfilter_ipv4/ip_set_jhash.h
724--- a/include/linux/netfilter_ipv4/ip_set_jhash.h 1970-01-01 01:00:00.000000000 +0100
725+++ linux-2.6/include/linux/netfilter_ipv4/ip_set_jhash.h 2008-07-08 16:52:53.465235839 +0200
1aedc22c 726@@ -0,0 +1,148 @@
727+#ifndef _LINUX_IPSET_JHASH_H
728+#define _LINUX_IPSET_JHASH_H
729+
730+/* This is a copy of linux/jhash.h but the types u32/u8 are changed
731+ * to __u32/__u8 so that the header file can be included into
732+ * userspace code as well. Jozsef Kadlecsik (kadlec@blackhole.kfki.hu)
733+ */
734+
735+/* jhash.h: Jenkins hash support.
736+ *
737+ * Copyright (C) 1996 Bob Jenkins (bob_jenkins@burtleburtle.net)
738+ *
739+ * http://burtleburtle.net/bob/hash/
740+ *
741+ * These are the credits from Bob's sources:
742+ *
743+ * lookup2.c, by Bob Jenkins, December 1996, Public Domain.
744+ * hash(), hash2(), hash3, and mix() are externally useful functions.
745+ * Routines to test the hash are included if SELF_TEST is defined.
746+ * You can use this free for any purpose. It has no warranty.
747+ *
748+ * Copyright (C) 2003 David S. Miller (davem@redhat.com)
749+ *
750+ * I've modified Bob's hash to be useful in the Linux kernel, and
751+ * any bugs present are surely my fault. -DaveM
752+ */
753+
754+/* NOTE: Arguments are modified. */
755+#define __jhash_mix(a, b, c) \
756+{ \
757+ a -= b; a -= c; a ^= (c>>13); \
758+ b -= c; b -= a; b ^= (a<<8); \
759+ c -= a; c -= b; c ^= (b>>13); \
760+ a -= b; a -= c; a ^= (c>>12); \
761+ b -= c; b -= a; b ^= (a<<16); \
762+ c -= a; c -= b; c ^= (b>>5); \
763+ a -= b; a -= c; a ^= (c>>3); \
764+ b -= c; b -= a; b ^= (a<<10); \
765+ c -= a; c -= b; c ^= (b>>15); \
766+}
767+
768+/* The golden ration: an arbitrary value */
769+#define JHASH_GOLDEN_RATIO 0x9e3779b9
770+
771+/* The most generic version, hashes an arbitrary sequence
772+ * of bytes. No alignment or length assumptions are made about
773+ * the input key.
774+ */
775+static inline __u32 jhash(void *key, __u32 length, __u32 initval)
776+{
777+ __u32 a, b, c, len;
778+ __u8 *k = key;
779+
780+ len = length;
781+ a = b = JHASH_GOLDEN_RATIO;
782+ c = initval;
783+
784+ while (len >= 12) {
785+ a += (k[0] +((__u32)k[1]<<8) +((__u32)k[2]<<16) +((__u32)k[3]<<24));
786+ b += (k[4] +((__u32)k[5]<<8) +((__u32)k[6]<<16) +((__u32)k[7]<<24));
787+ c += (k[8] +((__u32)k[9]<<8) +((__u32)k[10]<<16)+((__u32)k[11]<<24));
788+
789+ __jhash_mix(a,b,c);
790+
791+ k += 12;
792+ len -= 12;
793+ }
794+
795+ c += length;
796+ switch (len) {
797+ case 11: c += ((__u32)k[10]<<24);
798+ case 10: c += ((__u32)k[9]<<16);
799+ case 9 : c += ((__u32)k[8]<<8);
800+ case 8 : b += ((__u32)k[7]<<24);
801+ case 7 : b += ((__u32)k[6]<<16);
802+ case 6 : b += ((__u32)k[5]<<8);
803+ case 5 : b += k[4];
804+ case 4 : a += ((__u32)k[3]<<24);
805+ case 3 : a += ((__u32)k[2]<<16);
806+ case 2 : a += ((__u32)k[1]<<8);
807+ case 1 : a += k[0];
808+ };
809+
810+ __jhash_mix(a,b,c);
811+
812+ return c;
813+}
814+
815+/* A special optimized version that handles 1 or more of __u32s.
816+ * The length parameter here is the number of __u32s in the key.
817+ */
818+static inline __u32 jhash2(__u32 *k, __u32 length, __u32 initval)
819+{
820+ __u32 a, b, c, len;
821+
822+ a = b = JHASH_GOLDEN_RATIO;
823+ c = initval;
824+ len = length;
825+
826+ while (len >= 3) {
827+ a += k[0];
828+ b += k[1];
829+ c += k[2];
830+ __jhash_mix(a, b, c);
831+ k += 3; len -= 3;
832+ }
833+
834+ c += length * 4;
835+
836+ switch (len) {
837+ case 2 : b += k[1];
838+ case 1 : a += k[0];
839+ };
840+
841+ __jhash_mix(a,b,c);
842+
843+ return c;
844+}
845+
846+
847+/* A special ultra-optimized versions that knows they are hashing exactly
848+ * 3, 2 or 1 word(s).
849+ *
850+ * NOTE: In partilar the "c += length; __jhash_mix(a,b,c);" normally
851+ * done at the end is not done here.
852+ */
853+static inline __u32 jhash_3words(__u32 a, __u32 b, __u32 c, __u32 initval)
854+{
855+ a += JHASH_GOLDEN_RATIO;
856+ b += JHASH_GOLDEN_RATIO;
857+ c += initval;
858+
859+ __jhash_mix(a, b, c);
860+
861+ return c;
862+}
863+
864+static inline __u32 jhash_2words(__u32 a, __u32 b, __u32 initval)
865+{
866+ return jhash_3words(a, b, 0, initval);
867+}
868+
869+static inline __u32 jhash_1word(__u32 a, __u32 initval)
870+{
871+ return jhash_3words(a, 0, 0, initval);
872+}
873+
874+#endif /* _LINUX_IPSET_JHASH_H */
7d2f026e 875diff -uNrp --exclude=.svn a/include/linux/netfilter_ipv4/ip_set_macipmap.h linux-2.6/include/linux/netfilter_ipv4/ip_set_macipmap.h
876--- a/include/linux/netfilter_ipv4/ip_set_macipmap.h 1970-01-01 01:00:00.000000000 +0100
877+++ linux-2.6/include/linux/netfilter_ipv4/ip_set_macipmap.h 2008-07-08 16:52:53.465235839 +0200
1aedc22c 878@@ -0,0 +1,38 @@
879+#ifndef __IP_SET_MACIPMAP_H
880+#define __IP_SET_MACIPMAP_H
881+
882+#include <linux/netfilter_ipv4/ip_set.h>
883+
884+#define SETTYPE_NAME "macipmap"
885+#define MAX_RANGE 0x0000FFFF
886+
887+/* general flags */
888+#define IPSET_MACIP_MATCHUNSET 1
889+
890+/* per ip flags */
891+#define IPSET_MACIP_ISSET 1
892+
893+struct ip_set_macipmap {
894+ void *members; /* the macipmap proper */
895+ ip_set_ip_t first_ip; /* host byte order, included in range */
896+ ip_set_ip_t last_ip; /* host byte order, included in range */
897+ u_int32_t flags;
898+};
899+
900+struct ip_set_req_macipmap_create {
901+ ip_set_ip_t from;
902+ ip_set_ip_t to;
903+ u_int32_t flags;
904+};
905+
906+struct ip_set_req_macipmap {
907+ ip_set_ip_t ip;
908+ unsigned char ethernet[ETH_ALEN];
909+};
910+
911+struct ip_set_macip {
912+ unsigned short flags;
913+ unsigned char ethernet[ETH_ALEN];
914+};
915+
916+#endif /* __IP_SET_MACIPMAP_H */
7d2f026e 917diff -uNrp --exclude=.svn a/include/linux/netfilter_ipv4/ip_set_malloc.h linux-2.6/include/linux/netfilter_ipv4/ip_set_malloc.h
918--- a/include/linux/netfilter_ipv4/ip_set_malloc.h 1970-01-01 01:00:00.000000000 +0100
919+++ linux-2.6/include/linux/netfilter_ipv4/ip_set_malloc.h 2008-07-08 16:52:53.465235839 +0200
920@@ -0,0 +1,143 @@
1aedc22c 921+#ifndef _IP_SET_MALLOC_H
922+#define _IP_SET_MALLOC_H
923+
924+#ifdef __KERNEL__
925+
7d2f026e 926+static size_t max_malloc_size = 0, max_page_size = 0;
1aedc22c 927+
7d2f026e 928+static inline bool init_max_page_size(void)
1aedc22c 929+{
7d2f026e 930+ size_t page_size = 0;
931+
932+#define CACHE(x) if (max_page_size == 0 || x < max_page_size) \
933+ page_size = x;
1aedc22c 934+#include <linux/kmalloc_sizes.h>
935+#undef CACHE
7d2f026e 936+ if (page_size) {
937+ if (max_malloc_size == 0)
938+ max_malloc_size = page_size;
1aedc22c 939+
7d2f026e 940+ max_page_size = page_size;
1aedc22c 941+
7d2f026e 942+ return 1;
943+ }
944+ return 0;
1aedc22c 945+}
946+
947+struct harray {
948+ size_t max_elements;
949+ void *arrays[0];
950+};
951+
952+static inline void *
7d2f026e 953+__harray_malloc(size_t hashsize, size_t typesize, int flags)
1aedc22c 954+{
955+ struct harray *harray;
956+ size_t max_elements, size, i, j;
957+
7d2f026e 958+ BUG_ON(max_page_size == 0);
1aedc22c 959+
7d2f026e 960+ if (typesize > max_page_size)
1aedc22c 961+ return NULL;
962+
7d2f026e 963+ max_elements = max_page_size/typesize;
1aedc22c 964+ size = hashsize/max_elements;
965+ if (hashsize % max_elements)
966+ size++;
967+
968+ /* Last pointer signals end of arrays */
969+ harray = kmalloc(sizeof(struct harray) + (size + 1) * sizeof(void *),
970+ flags);
971+
972+ if (!harray)
973+ return NULL;
974+
975+ for (i = 0; i < size - 1; i++) {
976+ harray->arrays[i] = kmalloc(max_elements * typesize, flags);
977+ if (!harray->arrays[i])
978+ goto undo;
979+ memset(harray->arrays[i], 0, max_elements * typesize);
980+ }
981+ harray->arrays[i] = kmalloc((hashsize - i * max_elements) * typesize,
982+ flags);
983+ if (!harray->arrays[i])
984+ goto undo;
985+ memset(harray->arrays[i], 0, (hashsize - i * max_elements) * typesize);
986+
987+ harray->max_elements = max_elements;
988+ harray->arrays[size] = NULL;
989+
990+ return (void *)harray;
991+
992+ undo:
993+ for (j = 0; j < i; j++) {
994+ kfree(harray->arrays[j]);
995+ }
996+ kfree(harray);
997+ return NULL;
998+}
999+
7d2f026e 1000+static inline void *
1001+harray_malloc(size_t hashsize, size_t typesize, int flags)
1002+{
1003+ void *harray;
1004+
1005+ do {
1006+ harray = __harray_malloc(hashsize, typesize, flags|__GFP_NOWARN);
1007+ } while (harray == NULL && init_max_page_size());
1008+
1009+ return harray;
1010+}
1011+
1aedc22c 1012+static inline void harray_free(void *h)
1013+{
1014+ struct harray *harray = (struct harray *) h;
1015+ size_t i;
1016+
1017+ for (i = 0; harray->arrays[i] != NULL; i++)
1018+ kfree(harray->arrays[i]);
1019+ kfree(harray);
1020+}
1021+
1022+static inline void harray_flush(void *h, size_t hashsize, size_t typesize)
1023+{
1024+ struct harray *harray = (struct harray *) h;
1025+ size_t i;
1026+
1027+ for (i = 0; harray->arrays[i+1] != NULL; i++)
1028+ memset(harray->arrays[i], 0, harray->max_elements * typesize);
1029+ memset(harray->arrays[i], 0,
1030+ (hashsize - i * harray->max_elements) * typesize);
1031+}
1032+
1033+#define HARRAY_ELEM(h, type, which) \
1034+({ \
1035+ struct harray *__h = (struct harray *)(h); \
1036+ ((type)((__h)->arrays[(which)/(__h)->max_elements]) \
1037+ + (which)%(__h)->max_elements); \
1038+})
1039+
7d2f026e 1040+/* General memory allocation and deallocation */
1041+static inline void * ip_set_malloc(size_t bytes)
1042+{
1043+ BUG_ON(max_malloc_size == 0);
1044+
1045+ if (bytes > max_malloc_size)
1046+ return vmalloc(bytes);
1047+ else
1048+ return kmalloc(bytes, GFP_KERNEL | __GFP_NOWARN);
1049+}
1050+
1051+static inline void ip_set_free(void * data, size_t bytes)
1052+{
1053+ BUG_ON(max_malloc_size == 0);
1054+
1055+ if (bytes > max_malloc_size)
1056+ vfree(data);
1057+ else
1058+ kfree(data);
1059+}
1060+
1aedc22c 1061+#endif /* __KERNEL__ */
1062+
1063+#endif /*_IP_SET_MALLOC_H*/
7d2f026e 1064diff -uNrp --exclude=.svn a/include/linux/netfilter_ipv4/ip_set_nethash.h linux-2.6/include/linux/netfilter_ipv4/ip_set_nethash.h
1065--- a/include/linux/netfilter_ipv4/ip_set_nethash.h 1970-01-01 01:00:00.000000000 +0100
1066+++ linux-2.6/include/linux/netfilter_ipv4/ip_set_nethash.h 2008-07-08 16:52:53.465235839 +0200
1aedc22c 1067@@ -0,0 +1,55 @@
1068+#ifndef __IP_SET_NETHASH_H
1069+#define __IP_SET_NETHASH_H
1070+
1071+#include <linux/netfilter_ipv4/ip_set.h>
1072+
1073+#define SETTYPE_NAME "nethash"
1074+#define MAX_RANGE 0x0000FFFF
1075+
1076+struct ip_set_nethash {
1077+ ip_set_ip_t *members; /* the nethash proper */
1078+ uint32_t elements; /* number of elements */
1079+ uint32_t hashsize; /* hash size */
1080+ uint16_t probes; /* max number of probes */
1081+ uint16_t resize; /* resize factor in percent */
1082+ unsigned char cidr[30]; /* CIDR sizes */
1083+ void *initval[0]; /* initvals for jhash_1word */
1084+};
1085+
1086+struct ip_set_req_nethash_create {
1087+ uint32_t hashsize;
1088+ uint16_t probes;
1089+ uint16_t resize;
1090+};
1091+
1092+struct ip_set_req_nethash {
1093+ ip_set_ip_t ip;
1094+ unsigned char cidr;
1095+};
1096+
1097+static unsigned char shifts[] = {255, 253, 249, 241, 225, 193, 129, 1};
1098+
1099+static inline ip_set_ip_t
1100+pack(ip_set_ip_t ip, unsigned char cidr)
1101+{
1102+ ip_set_ip_t addr, *paddr = &addr;
1103+ unsigned char n, t, *a;
1104+
1105+ addr = htonl(ip & (0xFFFFFFFF << (32 - (cidr))));
1106+#ifdef __KERNEL__
1107+ DP("ip:%u.%u.%u.%u/%u", NIPQUAD(addr), cidr);
1108+#endif
1109+ n = cidr / 8;
1110+ t = cidr % 8;
1111+ a = &((unsigned char *)paddr)[n];
1112+ *a = *a /(1 << (8 - t)) + shifts[t];
1113+#ifdef __KERNEL__
1114+ DP("n: %u, t: %u, a: %u", n, t, *a);
1115+ DP("ip:%u.%u.%u.%u/%u, %u.%u.%u.%u",
1116+ HIPQUAD(ip), cidr, NIPQUAD(addr));
1117+#endif
1118+
1119+ return ntohl(addr);
1120+}
1121+
1122+#endif /* __IP_SET_NETHASH_H */
7d2f026e 1123diff -uNrp --exclude=.svn a/include/linux/netfilter_ipv4/ip_set_portmap.h linux-2.6/include/linux/netfilter_ipv4/ip_set_portmap.h
1124--- a/include/linux/netfilter_ipv4/ip_set_portmap.h 1970-01-01 01:00:00.000000000 +0100
1125+++ linux-2.6/include/linux/netfilter_ipv4/ip_set_portmap.h 2008-07-08 16:52:53.465235839 +0200
1aedc22c 1126@@ -0,0 +1,25 @@
1127+#ifndef __IP_SET_PORTMAP_H
1128+#define __IP_SET_PORTMAP_H
1129+
1130+#include <linux/netfilter_ipv4/ip_set.h>
1131+
1132+#define SETTYPE_NAME "portmap"
1133+#define MAX_RANGE 0x0000FFFF
1134+#define INVALID_PORT (MAX_RANGE + 1)
1135+
1136+struct ip_set_portmap {
1137+ void *members; /* the portmap proper */
1138+ ip_set_ip_t first_port; /* host byte order, included in range */
1139+ ip_set_ip_t last_port; /* host byte order, included in range */
1140+};
1141+
1142+struct ip_set_req_portmap_create {
1143+ ip_set_ip_t from;
1144+ ip_set_ip_t to;
1145+};
1146+
1147+struct ip_set_req_portmap {
1148+ ip_set_ip_t port;
1149+};
1150+
1151+#endif /* __IP_SET_PORTMAP_H */
7d2f026e 1152diff -uNrp --exclude=.svn a/include/linux/netfilter_ipv4/ipt_set.h linux-2.6/include/linux/netfilter_ipv4/ipt_set.h
1153--- a/include/linux/netfilter_ipv4/ipt_set.h 1970-01-01 01:00:00.000000000 +0100
1154+++ linux-2.6/include/linux/netfilter_ipv4/ipt_set.h 2008-07-08 16:52:53.465235839 +0200
1aedc22c 1155@@ -0,0 +1,21 @@
1156+#ifndef _IPT_SET_H
1157+#define _IPT_SET_H
1158+
1159+#include <linux/netfilter_ipv4/ip_set.h>
1160+
1161+struct ipt_set_info {
1162+ ip_set_id_t index;
1163+ u_int32_t flags[IP_SET_MAX_BINDINGS + 1];
1164+};
1165+
1166+/* match info */
1167+struct ipt_set_info_match {
1168+ struct ipt_set_info match_set;
1169+};
1170+
1171+struct ipt_set_info_target {
1172+ struct ipt_set_info add_set;
1173+ struct ipt_set_info del_set;
1174+};
1175+
1176+#endif /*_IPT_SET_H*/
7d2f026e 1177diff -uNrp --exclude=.svn a/net/ipv4/netfilter/ip_set.c linux-2.6/net/ipv4/netfilter/ip_set.c
1178--- a/net/ipv4/netfilter/ip_set.c 1970-01-01 01:00:00.000000000 +0100
1179+++ linux-2.6/net/ipv4/netfilter/ip_set.c 2008-07-08 16:52:53.965201208 +0200
1180@@ -0,0 +1,1981 @@
1aedc22c 1181+/* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu>
1182+ * Patrick Schaaf <bof@bof.de>
1183+ * Copyright (C) 2003-2004 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
1184+ *
1185+ * This program is free software; you can redistribute it and/or modify
1186+ * it under the terms of the GNU General Public License version 2 as
7d2f026e 1187+ * published by the Free Software Foundation.
1aedc22c 1188+ */
1189+
1190+/* Kernel module for IP set management */
1191+
1192+#include <linux/version.h>
1193+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
1194+#include <linux/config.h>
1195+#endif
1196+#include <linux/module.h>
1197+#include <linux/moduleparam.h>
1198+#include <linux/kmod.h>
1199+#include <linux/ip.h>
1200+#include <linux/skbuff.h>
1201+#include <linux/random.h>
f45e9687 1202+#include <linux/jhash.h>
1aedc22c 1203+#include <linux/netfilter_ipv4/ip_tables.h>
1204+#include <linux/errno.h>
1205+#include <asm/uaccess.h>
1206+#include <asm/bitops.h>
1207+#include <asm/semaphore.h>
1208+#include <linux/spinlock.h>
1209+#include <linux/vmalloc.h>
1210+
1211+#define ASSERT_READ_LOCK(x)
1212+#define ASSERT_WRITE_LOCK(x)
1213+#include <linux/netfilter_ipv4/ip_set.h>
1214+
1215+static struct list_head set_type_list; /* all registered sets */
1216+static struct ip_set **ip_set_list; /* all individual sets */
1217+static DEFINE_RWLOCK(ip_set_lock); /* protects the lists and the hash */
1218+static DECLARE_MUTEX(ip_set_app_mutex); /* serializes user access */
1219+static ip_set_id_t ip_set_max = CONFIG_IP_NF_SET_MAX;
1220+static ip_set_id_t ip_set_bindings_hash_size = CONFIG_IP_NF_SET_HASHSIZE;
1221+static struct list_head *ip_set_hash; /* hash of bindings */
1222+static unsigned int ip_set_hash_random; /* random seed */
1223+
7d2f026e 1224+#define SETNAME_EQ(a,b) (strncmp(a,b,IP_SET_MAXNAMELEN) == 0)
1225+
1aedc22c 1226+/*
1227+ * Sets are identified either by the index in ip_set_list or by id.
7d2f026e 1228+ * The id never changes and is used to find a key in the hash.
1229+ * The index may change by swapping and used at all other places
1aedc22c 1230+ * (set/SET netfilter modules, binding value, etc.)
1231+ *
1232+ * Userspace requests are serialized by ip_set_mutex and sets can
7d2f026e 1233+ * be deleted only from userspace. Therefore ip_set_list locking
1aedc22c 1234+ * must obey the following rules:
1235+ *
1236+ * - kernel requests: read and write locking mandatory
1237+ * - user requests: read locking optional, write locking mandatory
1238+ */
1239+
1240+static inline void
1241+__ip_set_get(ip_set_id_t index)
1242+{
1243+ atomic_inc(&ip_set_list[index]->ref);
1244+}
1245+
1246+static inline void
1247+__ip_set_put(ip_set_id_t index)
1248+{
1249+ atomic_dec(&ip_set_list[index]->ref);
1250+}
1251+
1252+/*
1253+ * Binding routines
1254+ */
1255+
1256+static inline struct ip_set_hash *
1257+__ip_set_find(u_int32_t key, ip_set_id_t id, ip_set_ip_t ip)
1258+{
1259+ struct ip_set_hash *set_hash;
1260+
1261+ list_for_each_entry(set_hash, &ip_set_hash[key], list)
1262+ if (set_hash->id == id && set_hash->ip == ip)
1263+ return set_hash;
1264+
1265+ return NULL;
1266+}
1267+
1268+static ip_set_id_t
1269+ip_set_find_in_hash(ip_set_id_t id, ip_set_ip_t ip)
1270+{
7d2f026e 1271+ u_int32_t key = jhash_2words(id, ip, ip_set_hash_random)
1aedc22c 1272+ % ip_set_bindings_hash_size;
1273+ struct ip_set_hash *set_hash;
1274+
1275+ ASSERT_READ_LOCK(&ip_set_lock);
1276+ IP_SET_ASSERT(ip_set_list[id]);
1277+ DP("set: %s, ip: %u.%u.%u.%u", ip_set_list[id]->name, HIPQUAD(ip));
1278+
1279+ set_hash = __ip_set_find(key, id, ip);
1280+
7d2f026e 1281+ DP("set: %s, ip: %u.%u.%u.%u, binding: %s", ip_set_list[id]->name,
1aedc22c 1282+ HIPQUAD(ip),
1283+ set_hash != NULL ? ip_set_list[set_hash->binding]->name : "");
1284+
1285+ return (set_hash != NULL ? set_hash->binding : IP_SET_INVALID_ID);
1286+}
1287+
7d2f026e 1288+static inline void
1aedc22c 1289+__set_hash_del(struct ip_set_hash *set_hash)
1290+{
1291+ ASSERT_WRITE_LOCK(&ip_set_lock);
1292+ IP_SET_ASSERT(ip_set_list[set_hash->binding]);
1293+
1294+ __ip_set_put(set_hash->binding);
1295+ list_del(&set_hash->list);
1296+ kfree(set_hash);
1297+}
1298+
1299+static int
1300+ip_set_hash_del(ip_set_id_t id, ip_set_ip_t ip)
1301+{
1302+ u_int32_t key = jhash_2words(id, ip, ip_set_hash_random)
1303+ % ip_set_bindings_hash_size;
1304+ struct ip_set_hash *set_hash;
1305+
1306+ IP_SET_ASSERT(ip_set_list[id]);
1307+ DP("set: %s, ip: %u.%u.%u.%u", ip_set_list[id]->name, HIPQUAD(ip));
1308+ write_lock_bh(&ip_set_lock);
1309+ set_hash = __ip_set_find(key, id, ip);
1310+ DP("set: %s, ip: %u.%u.%u.%u, binding: %s", ip_set_list[id]->name,
1311+ HIPQUAD(ip),
1312+ set_hash != NULL ? ip_set_list[set_hash->binding]->name : "");
1313+
1314+ if (set_hash != NULL)
1315+ __set_hash_del(set_hash);
1316+ write_unlock_bh(&ip_set_lock);
1317+ return 0;
1318+}
1319+
7d2f026e 1320+static int
1aedc22c 1321+ip_set_hash_add(ip_set_id_t id, ip_set_ip_t ip, ip_set_id_t binding)
1322+{
1323+ u_int32_t key = jhash_2words(id, ip, ip_set_hash_random)
1324+ % ip_set_bindings_hash_size;
1325+ struct ip_set_hash *set_hash;
1326+ int ret = 0;
1327+
1328+ IP_SET_ASSERT(ip_set_list[id]);
1329+ IP_SET_ASSERT(ip_set_list[binding]);
7d2f026e 1330+ DP("set: %s, ip: %u.%u.%u.%u, binding: %s", ip_set_list[id]->name,
1aedc22c 1331+ HIPQUAD(ip), ip_set_list[binding]->name);
1332+ write_lock_bh(&ip_set_lock);
1333+ set_hash = __ip_set_find(key, id, ip);
1334+ if (!set_hash) {
9f54053a 1335+ set_hash = kmalloc(sizeof(struct ip_set_hash), GFP_ATOMIC);
1aedc22c 1336+ if (!set_hash) {
1337+ ret = -ENOMEM;
1338+ goto unlock;
1339+ }
1340+ INIT_LIST_HEAD(&set_hash->list);
1341+ set_hash->id = id;
1342+ set_hash->ip = ip;
9f54053a 1343+ list_add(&set_hash->list, &ip_set_hash[key]);
1aedc22c 1344+ } else {
1345+ IP_SET_ASSERT(ip_set_list[set_hash->binding]);
1346+ DP("overwrite binding: %s",
1347+ ip_set_list[set_hash->binding]->name);
1348+ __ip_set_put(set_hash->binding);
1349+ }
1350+ set_hash->binding = binding;
1351+ __ip_set_get(set_hash->binding);
9f54053a
JR
1352+ DP("stored: key %u, id %u (%s), ip %u.%u.%u.%u, binding %u (%s)",
1353+ key, id, ip_set_list[id]->name,
1354+ HIPQUAD(ip), binding, ip_set_list[binding]->name);
1aedc22c 1355+ unlock:
1356+ write_unlock_bh(&ip_set_lock);
1357+ return ret;
1358+}
1359+
1360+#define FOREACH_HASH_DO(fn, args...) \
1361+({ \
1362+ ip_set_id_t __key; \
1363+ struct ip_set_hash *__set_hash; \
1364+ \
1365+ for (__key = 0; __key < ip_set_bindings_hash_size; __key++) { \
1366+ list_for_each_entry(__set_hash, &ip_set_hash[__key], list) \
1367+ fn(__set_hash , ## args); \
1368+ } \
1369+})
1370+
1371+#define FOREACH_HASH_RW_DO(fn, args...) \
1372+({ \
1373+ ip_set_id_t __key; \
1374+ struct ip_set_hash *__set_hash, *__n; \
1375+ \
1376+ ASSERT_WRITE_LOCK(&ip_set_lock); \
1377+ for (__key = 0; __key < ip_set_bindings_hash_size; __key++) { \
1378+ list_for_each_entry_safe(__set_hash, __n, &ip_set_hash[__key], list)\
1379+ fn(__set_hash , ## args); \
1380+ } \
1381+})
1382+
1383+/* Add, del and test set entries from kernel */
1384+
1385+#define follow_bindings(index, set, ip) \
1386+((index = ip_set_find_in_hash((set)->id, ip)) != IP_SET_INVALID_ID \
1387+ || (index = (set)->binding) != IP_SET_INVALID_ID)
1388+
1389+int
1390+ip_set_testip_kernel(ip_set_id_t index,
1391+ const struct sk_buff *skb,
1392+ const u_int32_t *flags)
1393+{
1394+ struct ip_set *set;
1395+ ip_set_ip_t ip;
1396+ int res;
1397+ unsigned char i = 0;
1398+
1399+ IP_SET_ASSERT(flags[i]);
1400+ read_lock_bh(&ip_set_lock);
1401+ do {
1402+ set = ip_set_list[index];
1403+ IP_SET_ASSERT(set);
1404+ DP("set %s, index %u", set->name, index);
1405+ read_lock_bh(&set->lock);
1406+ res = set->type->testip_kernel(set, skb, &ip, flags, i++);
1407+ read_unlock_bh(&set->lock);
1408+ i += !!(set->type->features & IPSET_DATA_DOUBLE);
7d2f026e 1409+ } while (res > 0
1410+ && flags[i]
1aedc22c 1411+ && follow_bindings(index, set, ip));
1412+ read_unlock_bh(&ip_set_lock);
1413+
1414+ return res;
1415+}
1416+
1417+void
1418+ip_set_addip_kernel(ip_set_id_t index,
1419+ const struct sk_buff *skb,
1420+ const u_int32_t *flags)
1421+{
1422+ struct ip_set *set;
1423+ ip_set_ip_t ip;
1424+ int res;
1425+ unsigned char i = 0;
1426+
1427+ IP_SET_ASSERT(flags[i]);
1428+ retry:
1429+ read_lock_bh(&ip_set_lock);
1430+ do {
1431+ set = ip_set_list[index];
1432+ IP_SET_ASSERT(set);
1433+ DP("set %s, index %u", set->name, index);
1434+ write_lock_bh(&set->lock);
1435+ res = set->type->addip_kernel(set, skb, &ip, flags, i++);
1436+ write_unlock_bh(&set->lock);
1437+ i += !!(set->type->features & IPSET_DATA_DOUBLE);
1438+ } while ((res == 0 || res == -EEXIST)
7d2f026e 1439+ && flags[i]
1aedc22c 1440+ && follow_bindings(index, set, ip));
1441+ read_unlock_bh(&ip_set_lock);
1442+
1443+ if (res == -EAGAIN
1444+ && set->type->retry
1445+ && (res = set->type->retry(set)) == 0)
1446+ goto retry;
1447+}
1448+
1449+void
1450+ip_set_delip_kernel(ip_set_id_t index,
1451+ const struct sk_buff *skb,
1452+ const u_int32_t *flags)
1453+{
1454+ struct ip_set *set;
1455+ ip_set_ip_t ip;
1456+ int res;
1457+ unsigned char i = 0;
1458+
1459+ IP_SET_ASSERT(flags[i]);
1460+ read_lock_bh(&ip_set_lock);
1461+ do {
1462+ set = ip_set_list[index];
1463+ IP_SET_ASSERT(set);
1464+ DP("set %s, index %u", set->name, index);
1465+ write_lock_bh(&set->lock);
1466+ res = set->type->delip_kernel(set, skb, &ip, flags, i++);
1467+ write_unlock_bh(&set->lock);
1468+ i += !!(set->type->features & IPSET_DATA_DOUBLE);
1469+ } while ((res == 0 || res == -EEXIST)
7d2f026e 1470+ && flags[i]
1aedc22c 1471+ && follow_bindings(index, set, ip));
1472+ read_unlock_bh(&ip_set_lock);
1473+}
1474+
1475+/* Register and deregister settype */
1476+
1477+static inline struct ip_set_type *
1478+find_set_type(const char *name)
1479+{
1480+ struct ip_set_type *set_type;
1481+
1482+ list_for_each_entry(set_type, &set_type_list, list)
1483+ if (!strncmp(set_type->typename, name, IP_SET_MAXNAMELEN - 1))
1484+ return set_type;
1485+ return NULL;
1486+}
1487+
7d2f026e 1488+int
1aedc22c 1489+ip_set_register_set_type(struct ip_set_type *set_type)
1490+{
1491+ int ret = 0;
1492+
1493+ if (set_type->protocol_version != IP_SET_PROTOCOL_VERSION) {
1494+ ip_set_printk("'%s' uses wrong protocol version %u (want %u)",
1495+ set_type->typename,
1496+ set_type->protocol_version,
1497+ IP_SET_PROTOCOL_VERSION);
1498+ return -EINVAL;
1499+ }
1500+
1501+ write_lock_bh(&ip_set_lock);
1502+ if (find_set_type(set_type->typename)) {
1503+ /* Duplicate! */
7d2f026e 1504+ ip_set_printk("'%s' already registered!",
1aedc22c 1505+ set_type->typename);
1506+ ret = -EINVAL;
1507+ goto unlock;
1508+ }
1509+ if (!try_module_get(THIS_MODULE)) {
1510+ ret = -EFAULT;
1511+ goto unlock;
1512+ }
1513+ list_add(&set_type->list, &set_type_list);
1514+ DP("'%s' registered.", set_type->typename);
1515+ unlock:
1516+ write_unlock_bh(&ip_set_lock);
1517+ return ret;
1518+}
1519+
1520+void
1521+ip_set_unregister_set_type(struct ip_set_type *set_type)
1522+{
1523+ write_lock_bh(&ip_set_lock);
1524+ if (!find_set_type(set_type->typename)) {
1525+ ip_set_printk("'%s' not registered?",
1526+ set_type->typename);
1527+ goto unlock;
1528+ }
1529+ list_del(&set_type->list);
1530+ module_put(THIS_MODULE);
1531+ DP("'%s' unregistered.", set_type->typename);
1532+ unlock:
1533+ write_unlock_bh(&ip_set_lock);
1534+
1535+}
1536+
1537+/*
1538+ * Userspace routines
1539+ */
1540+
1541+/*
1542+ * Find set by name, reference it once. The reference makes sure the
1543+ * thing pointed to, does not go away under our feet. Drop the reference
1544+ * later, using ip_set_put().
1545+ */
1546+ip_set_id_t
1547+ip_set_get_byname(const char *name)
1548+{
1549+ ip_set_id_t i, index = IP_SET_INVALID_ID;
1550+
1551+ down(&ip_set_app_mutex);
1552+ for (i = 0; i < ip_set_max; i++) {
1553+ if (ip_set_list[i] != NULL
7d2f026e 1554+ && SETNAME_EQ(ip_set_list[i]->name, name)) {
1aedc22c 1555+ __ip_set_get(i);
1556+ index = i;
1557+ break;
1558+ }
1559+ }
1560+ up(&ip_set_app_mutex);
1561+ return index;
1562+}
1563+
1564+/*
1565+ * Find set by index, reference it once. The reference makes sure the
1566+ * thing pointed to, does not go away under our feet. Drop the reference
1567+ * later, using ip_set_put().
1568+ */
1569+ip_set_id_t
1570+ip_set_get_byindex(ip_set_id_t index)
1571+{
1572+ down(&ip_set_app_mutex);
1573+
1574+ if (index >= ip_set_max)
1575+ return IP_SET_INVALID_ID;
1576+
1577+ if (ip_set_list[index])
1578+ __ip_set_get(index);
1579+ else
1580+ index = IP_SET_INVALID_ID;
1581+
1582+ up(&ip_set_app_mutex);
1583+ return index;
1584+}
1585+
1586+/*
1587+ * If the given set pointer points to a valid set, decrement
1588+ * reference count by 1. The caller shall not assume the index
1589+ * to be valid, after calling this function.
1590+ */
1591+void ip_set_put(ip_set_id_t index)
1592+{
1593+ down(&ip_set_app_mutex);
1594+ if (ip_set_list[index])
1595+ __ip_set_put(index);
1596+ up(&ip_set_app_mutex);
1597+}
1598+
1599+/* Find a set by name or index */
1600+static ip_set_id_t
1601+ip_set_find_byname(const char *name)
1602+{
1603+ ip_set_id_t i, index = IP_SET_INVALID_ID;
1604+
1605+ for (i = 0; i < ip_set_max; i++) {
1606+ if (ip_set_list[i] != NULL
7d2f026e 1607+ && SETNAME_EQ(ip_set_list[i]->name, name)) {
1aedc22c 1608+ index = i;
1609+ break;
1610+ }
1611+ }
1612+ return index;
1613+}
1614+
1615+static ip_set_id_t
1616+ip_set_find_byindex(ip_set_id_t index)
1617+{
1618+ if (index >= ip_set_max || ip_set_list[index] == NULL)
1619+ index = IP_SET_INVALID_ID;
1620+
1621+ return index;
1622+}
1623+
1624+/*
1625+ * Add, del, test, bind and unbind
1626+ */
1627+
1628+static inline int
1629+__ip_set_testip(struct ip_set *set,
1630+ const void *data,
1631+ size_t size,
1632+ ip_set_ip_t *ip)
1633+{
1634+ int res;
1635+
1636+ read_lock_bh(&set->lock);
1637+ res = set->type->testip(set, data, size, ip);
1638+ read_unlock_bh(&set->lock);
1639+
1640+ return res;
1641+}
1642+
1643+static int
1644+__ip_set_addip(ip_set_id_t index,
1645+ const void *data,
1646+ size_t size)
1647+{
1648+ struct ip_set *set = ip_set_list[index];
1649+ ip_set_ip_t ip;
1650+ int res;
1651+
1652+ IP_SET_ASSERT(set);
1653+ do {
1654+ write_lock_bh(&set->lock);
1655+ res = set->type->addip(set, data, size, &ip);
1656+ write_unlock_bh(&set->lock);
1657+ } while (res == -EAGAIN
1658+ && set->type->retry
1659+ && (res = set->type->retry(set)) == 0);
1660+
1661+ return res;
1662+}
1663+
1664+static int
1665+ip_set_addip(ip_set_id_t index,
1666+ const void *data,
1667+ size_t size)
1668+{
1669+
1670+ return __ip_set_addip(index,
1671+ data + sizeof(struct ip_set_req_adt),
1672+ size - sizeof(struct ip_set_req_adt));
1673+}
1674+
1675+static int
1676+ip_set_delip(ip_set_id_t index,
1677+ const void *data,
1678+ size_t size)
1679+{
1680+ struct ip_set *set = ip_set_list[index];
1681+ ip_set_ip_t ip;
1682+ int res;
1683+
1684+ IP_SET_ASSERT(set);
1685+ write_lock_bh(&set->lock);
1686+ res = set->type->delip(set,
1687+ data + sizeof(struct ip_set_req_adt),
1688+ size - sizeof(struct ip_set_req_adt),
1689+ &ip);
1690+ write_unlock_bh(&set->lock);
1691+
1692+ return res;
1693+}
1694+
1695+static int
1696+ip_set_testip(ip_set_id_t index,
1697+ const void *data,
1698+ size_t size)
1699+{
1700+ struct ip_set *set = ip_set_list[index];
1701+ ip_set_ip_t ip;
1702+ int res;
1703+
1704+ IP_SET_ASSERT(set);
1705+ res = __ip_set_testip(set,
1706+ data + sizeof(struct ip_set_req_adt),
1707+ size - sizeof(struct ip_set_req_adt),
1708+ &ip);
1709+
1710+ return (res > 0 ? -EEXIST : res);
1711+}
1712+
1713+static int
1714+ip_set_bindip(ip_set_id_t index,
1715+ const void *data,
1716+ size_t size)
1717+{
1718+ struct ip_set *set = ip_set_list[index];
7d2f026e 1719+ const struct ip_set_req_bind *req_bind;
1aedc22c 1720+ ip_set_id_t binding;
1721+ ip_set_ip_t ip;
1722+ int res;
1723+
1724+ IP_SET_ASSERT(set);
1725+ if (size < sizeof(struct ip_set_req_bind))
1726+ return -EINVAL;
1727+
7d2f026e 1728+ req_bind = data;
1aedc22c 1729+
7d2f026e 1730+ if (SETNAME_EQ(req_bind->binding, IPSET_TOKEN_DEFAULT)) {
1aedc22c 1731+ /* Default binding of a set */
7d2f026e 1732+ const char *binding_name;
1aedc22c 1733+
1734+ if (size != sizeof(struct ip_set_req_bind) + IP_SET_MAXNAMELEN)
1735+ return -EINVAL;
1736+
7d2f026e 1737+ binding_name = data + sizeof(struct ip_set_req_bind);
1aedc22c 1738+
1739+ binding = ip_set_find_byname(binding_name);
1740+ if (binding == IP_SET_INVALID_ID)
1741+ return -ENOENT;
1742+
1743+ write_lock_bh(&ip_set_lock);
1744+ /* Sets as binding values are referenced */
1745+ if (set->binding != IP_SET_INVALID_ID)
1746+ __ip_set_put(set->binding);
1747+ set->binding = binding;
1748+ __ip_set_get(set->binding);
1749+ write_unlock_bh(&ip_set_lock);
1750+
1751+ return 0;
1752+ }
1753+ binding = ip_set_find_byname(req_bind->binding);
1754+ if (binding == IP_SET_INVALID_ID)
1755+ return -ENOENT;
1756+
1757+ res = __ip_set_testip(set,
1758+ data + sizeof(struct ip_set_req_bind),
1759+ size - sizeof(struct ip_set_req_bind),
1760+ &ip);
1761+ DP("set %s, ip: %u.%u.%u.%u, binding %s",
1762+ set->name, HIPQUAD(ip), ip_set_list[binding]->name);
1763+
1764+ if (res >= 0)
1765+ res = ip_set_hash_add(set->id, ip, binding);
1766+
1767+ return res;
1768+}
1769+
1770+#define FOREACH_SET_DO(fn, args...) \
1771+({ \
1772+ ip_set_id_t __i; \
1773+ struct ip_set *__set; \
1774+ \
1775+ for (__i = 0; __i < ip_set_max; __i++) { \
1776+ __set = ip_set_list[__i]; \
1777+ if (__set != NULL) \
1778+ fn(__set , ##args); \
1779+ } \
1780+})
1781+
1782+static inline void
1783+__set_hash_del_byid(struct ip_set_hash *set_hash, ip_set_id_t id)
1784+{
1785+ if (set_hash->id == id)
1786+ __set_hash_del(set_hash);
1787+}
1788+
1789+static inline void
1790+__unbind_default(struct ip_set *set)
1791+{
1792+ if (set->binding != IP_SET_INVALID_ID) {
1793+ /* Sets as binding values are referenced */
1794+ __ip_set_put(set->binding);
1795+ set->binding = IP_SET_INVALID_ID;
1796+ }
1797+}
1798+
1799+static int
1800+ip_set_unbindip(ip_set_id_t index,
1801+ const void *data,
1802+ size_t size)
1803+{
1804+ struct ip_set *set;
7d2f026e 1805+ const struct ip_set_req_bind *req_bind;
1aedc22c 1806+ ip_set_ip_t ip;
1807+ int res;
1808+
1809+ DP("");
1810+ if (size < sizeof(struct ip_set_req_bind))
1811+ return -EINVAL;
1812+
7d2f026e 1813+ req_bind = data;
1aedc22c 1814+
1815+ DP("%u %s", index, req_bind->binding);
1816+ if (index == IP_SET_INVALID_ID) {
1817+ /* unbind :all: */
7d2f026e 1818+ if (SETNAME_EQ(req_bind->binding, IPSET_TOKEN_DEFAULT)) {
1aedc22c 1819+ /* Default binding of sets */
1820+ write_lock_bh(&ip_set_lock);
1821+ FOREACH_SET_DO(__unbind_default);
1822+ write_unlock_bh(&ip_set_lock);
1823+ return 0;
7d2f026e 1824+ } else if (SETNAME_EQ(req_bind->binding, IPSET_TOKEN_ALL)) {
1aedc22c 1825+ /* Flush all bindings of all sets*/
1826+ write_lock_bh(&ip_set_lock);
1827+ FOREACH_HASH_RW_DO(__set_hash_del);
1828+ write_unlock_bh(&ip_set_lock);
1829+ return 0;
1830+ }
1831+ DP("unreachable reached!");
1832+ return -EINVAL;
1833+ }
1834+
1835+ set = ip_set_list[index];
1836+ IP_SET_ASSERT(set);
7d2f026e 1837+ if (SETNAME_EQ(req_bind->binding, IPSET_TOKEN_DEFAULT)) {
1aedc22c 1838+ /* Default binding of set */
1839+ ip_set_id_t binding = ip_set_find_byindex(set->binding);
1840+
1841+ if (binding == IP_SET_INVALID_ID)
1842+ return -ENOENT;
1843+
1844+ write_lock_bh(&ip_set_lock);
1845+ /* Sets in hash values are referenced */
1846+ __ip_set_put(set->binding);
1847+ set->binding = IP_SET_INVALID_ID;
1848+ write_unlock_bh(&ip_set_lock);
1849+
1850+ return 0;
7d2f026e 1851+ } else if (SETNAME_EQ(req_bind->binding, IPSET_TOKEN_ALL)) {
1aedc22c 1852+ /* Flush all bindings */
1853+
1854+ write_lock_bh(&ip_set_lock);
1855+ FOREACH_HASH_RW_DO(__set_hash_del_byid, set->id);
1856+ write_unlock_bh(&ip_set_lock);
1857+ return 0;
1858+ }
1859+
1860+ res = __ip_set_testip(set,
1861+ data + sizeof(struct ip_set_req_bind),
1862+ size - sizeof(struct ip_set_req_bind),
1863+ &ip);
1864+
1865+ DP("set %s, ip: %u.%u.%u.%u", set->name, HIPQUAD(ip));
1866+ if (res >= 0)
1867+ res = ip_set_hash_del(set->id, ip);
1868+
1869+ return res;
1870+}
1871+
1872+static int
1873+ip_set_testbind(ip_set_id_t index,
1874+ const void *data,
1875+ size_t size)
1876+{
1877+ struct ip_set *set = ip_set_list[index];
7d2f026e 1878+ const struct ip_set_req_bind *req_bind;
1aedc22c 1879+ ip_set_id_t binding;
1880+ ip_set_ip_t ip;
1881+ int res;
1882+
1883+ IP_SET_ASSERT(set);
1884+ if (size < sizeof(struct ip_set_req_bind))
1885+ return -EINVAL;
1886+
7d2f026e 1887+ req_bind = data;
1aedc22c 1888+
7d2f026e 1889+ if (SETNAME_EQ(req_bind->binding, IPSET_TOKEN_DEFAULT)) {
1aedc22c 1890+ /* Default binding of set */
7d2f026e 1891+ const char *binding_name;
1aedc22c 1892+
1893+ if (size != sizeof(struct ip_set_req_bind) + IP_SET_MAXNAMELEN)
1894+ return -EINVAL;
1895+
7d2f026e 1896+ binding_name = data + sizeof(struct ip_set_req_bind);
1aedc22c 1897+
1898+ binding = ip_set_find_byname(binding_name);
1899+ if (binding == IP_SET_INVALID_ID)
1900+ return -ENOENT;
1901+
1902+ res = (set->binding == binding) ? -EEXIST : 0;
1903+
1904+ return res;
1905+ }
1906+ binding = ip_set_find_byname(req_bind->binding);
1907+ if (binding == IP_SET_INVALID_ID)
1908+ return -ENOENT;
1909+
1910+
1911+ res = __ip_set_testip(set,
1912+ data + sizeof(struct ip_set_req_bind),
1913+ size - sizeof(struct ip_set_req_bind),
1914+ &ip);
1915+ DP("set %s, ip: %u.%u.%u.%u, binding %s",
1916+ set->name, HIPQUAD(ip), ip_set_list[binding]->name);
7d2f026e 1917+
1aedc22c 1918+ if (res >= 0)
1919+ res = (ip_set_find_in_hash(set->id, ip) == binding)
1920+ ? -EEXIST : 0;
1921+
1922+ return res;
1923+}
1924+
1925+static struct ip_set_type *
1926+find_set_type_rlock(const char *typename)
1927+{
1928+ struct ip_set_type *type;
1929+
1930+ read_lock_bh(&ip_set_lock);
1931+ type = find_set_type(typename);
1932+ if (type == NULL)
1933+ read_unlock_bh(&ip_set_lock);
1934+
1935+ return type;
1936+}
1937+
1938+static int
1939+find_free_id(const char *name,
1940+ ip_set_id_t *index,
1941+ ip_set_id_t *id)
1942+{
1943+ ip_set_id_t i;
1944+
1945+ *id = IP_SET_INVALID_ID;
1946+ for (i = 0; i < ip_set_max; i++) {
1947+ if (ip_set_list[i] == NULL) {
1948+ if (*id == IP_SET_INVALID_ID)
1949+ *id = *index = i;
7d2f026e 1950+ } else if (SETNAME_EQ(name, ip_set_list[i]->name))
1aedc22c 1951+ /* Name clash */
1952+ return -EEXIST;
1953+ }
1954+ if (*id == IP_SET_INVALID_ID)
1955+ /* No free slot remained */
1956+ return -ERANGE;
1957+ /* Check that index is usable as id (swapping) */
1958+ check:
1959+ for (i = 0; i < ip_set_max; i++) {
1960+ if (ip_set_list[i] != NULL
1961+ && ip_set_list[i]->id == *id) {
1962+ *id = i;
1963+ goto check;
1964+ }
1965+ }
1966+ return 0;
1967+}
1968+
1969+/*
1970+ * Create a set
1971+ */
1972+static int
1973+ip_set_create(const char *name,
1974+ const char *typename,
1975+ ip_set_id_t restore,
1976+ const void *data,
1977+ size_t size)
1978+{
1979+ struct ip_set *set;
1980+ ip_set_id_t index = 0, id;
1981+ int res = 0;
1982+
1983+ DP("setname: %s, typename: %s, id: %u", name, typename, restore);
1984+ /*
1985+ * First, and without any locks, allocate and initialize
1986+ * a normal base set structure.
1987+ */
1988+ set = kmalloc(sizeof(struct ip_set), GFP_KERNEL);
1989+ if (!set)
1990+ return -ENOMEM;
1991+ set->lock = RW_LOCK_UNLOCKED;
1992+ strncpy(set->name, name, IP_SET_MAXNAMELEN);
1993+ set->binding = IP_SET_INVALID_ID;
1994+ atomic_set(&set->ref, 0);
1995+
1996+ /*
1997+ * Next, take the &ip_set_lock, check that we know the type,
1998+ * and take a reference on the type, to make sure it
1999+ * stays available while constructing our new set.
2000+ *
2001+ * After referencing the type, we drop the &ip_set_lock,
2002+ * and let the new set construction run without locks.
2003+ */
2004+ set->type = find_set_type_rlock(typename);
2005+ if (set->type == NULL) {
2006+ /* Try loading the module */
2007+ char modulename[IP_SET_MAXNAMELEN + strlen("ip_set_") + 1];
2008+ strcpy(modulename, "ip_set_");
2009+ strcat(modulename, typename);
2010+ DP("try to load %s", modulename);
2011+ request_module(modulename);
2012+ set->type = find_set_type_rlock(typename);
2013+ }
2014+ if (set->type == NULL) {
2015+ ip_set_printk("no set type '%s', set '%s' not created",
2016+ typename, name);
2017+ res = -ENOENT;
2018+ goto out;
2019+ }
2020+ if (!try_module_get(set->type->me)) {
2021+ read_unlock_bh(&ip_set_lock);
2022+ res = -EFAULT;
2023+ goto out;
2024+ }
2025+ read_unlock_bh(&ip_set_lock);
2026+
2027+ /*
2028+ * Without holding any locks, create private part.
2029+ */
2030+ res = set->type->create(set, data, size);
2031+ if (res != 0)
2032+ goto put_out;
2033+
2034+ /* BTW, res==0 here. */
2035+
2036+ /*
2037+ * Here, we have a valid, constructed set. &ip_set_lock again,
7d2f026e 2038+ * find free id/index and check that it is not already in
1aedc22c 2039+ * ip_set_list.
2040+ */
2041+ write_lock_bh(&ip_set_lock);
2042+ if ((res = find_free_id(set->name, &index, &id)) != 0) {
2043+ DP("no free id!");
2044+ goto cleanup;
2045+ }
2046+
2047+ /* Make sure restore gets the same index */
2048+ if (restore != IP_SET_INVALID_ID && index != restore) {
2049+ DP("Can't restore, sets are screwed up");
2050+ res = -ERANGE;
2051+ goto cleanup;
2052+ }
7d2f026e 2053+
1aedc22c 2054+ /*
2055+ * Finally! Add our shiny new set to the list, and be done.
2056+ */
2057+ DP("create: '%s' created with index %u, id %u!", set->name, index, id);
2058+ set->id = id;
2059+ ip_set_list[index] = set;
2060+ write_unlock_bh(&ip_set_lock);
2061+ return res;
2062+
2063+ cleanup:
2064+ write_unlock_bh(&ip_set_lock);
2065+ set->type->destroy(set);
2066+ put_out:
2067+ module_put(set->type->me);
2068+ out:
2069+ kfree(set);
2070+ return res;
2071+}
2072+
2073+/*
2074+ * Destroy a given existing set
2075+ */
2076+static void
2077+ip_set_destroy_set(ip_set_id_t index)
2078+{
2079+ struct ip_set *set = ip_set_list[index];
2080+
2081+ IP_SET_ASSERT(set);
2082+ DP("set: %s", set->name);
2083+ write_lock_bh(&ip_set_lock);
2084+ FOREACH_HASH_RW_DO(__set_hash_del_byid, set->id);
2085+ if (set->binding != IP_SET_INVALID_ID)
2086+ __ip_set_put(set->binding);
2087+ ip_set_list[index] = NULL;
2088+ write_unlock_bh(&ip_set_lock);
2089+
2090+ /* Must call it without holding any lock */
2091+ set->type->destroy(set);
2092+ module_put(set->type->me);
2093+ kfree(set);
2094+}
2095+
2096+/*
2097+ * Destroy a set - or all sets
2098+ * Sets must not be referenced/used.
2099+ */
2100+static int
2101+ip_set_destroy(ip_set_id_t index)
2102+{
2103+ ip_set_id_t i;
2104+
2105+ /* ref modification always protected by the mutex */
2106+ if (index != IP_SET_INVALID_ID) {
2107+ if (atomic_read(&ip_set_list[index]->ref))
2108+ return -EBUSY;
2109+ ip_set_destroy_set(index);
2110+ } else {
2111+ for (i = 0; i < ip_set_max; i++) {
7d2f026e 2112+ if (ip_set_list[i] != NULL
1aedc22c 2113+ && (atomic_read(&ip_set_list[i]->ref)))
2114+ return -EBUSY;
2115+ }
2116+
2117+ for (i = 0; i < ip_set_max; i++) {
2118+ if (ip_set_list[i] != NULL)
2119+ ip_set_destroy_set(i);
2120+ }
2121+ }
2122+ return 0;
2123+}
2124+
2125+static void
2126+ip_set_flush_set(struct ip_set *set)
2127+{
2128+ DP("set: %s %u", set->name, set->id);
2129+
2130+ write_lock_bh(&set->lock);
2131+ set->type->flush(set);
2132+ write_unlock_bh(&set->lock);
2133+}
2134+
7d2f026e 2135+/*
1aedc22c 2136+ * Flush data in a set - or in all sets
2137+ */
2138+static int
2139+ip_set_flush(ip_set_id_t index)
2140+{
2141+ if (index != IP_SET_INVALID_ID) {
2142+ IP_SET_ASSERT(ip_set_list[index]);
2143+ ip_set_flush_set(ip_set_list[index]);
2144+ } else
2145+ FOREACH_SET_DO(ip_set_flush_set);
2146+
2147+ return 0;
2148+}
2149+
2150+/* Rename a set */
2151+static int
2152+ip_set_rename(ip_set_id_t index, const char *name)
2153+{
2154+ struct ip_set *set = ip_set_list[index];
2155+ ip_set_id_t i;
2156+ int res = 0;
2157+
2158+ DP("set: %s to %s", set->name, name);
2159+ write_lock_bh(&ip_set_lock);
2160+ for (i = 0; i < ip_set_max; i++) {
2161+ if (ip_set_list[i] != NULL
7d2f026e 2162+ && SETNAME_EQ(ip_set_list[i]->name, name)) {
1aedc22c 2163+ res = -EEXIST;
2164+ goto unlock;
2165+ }
2166+ }
2167+ strncpy(set->name, name, IP_SET_MAXNAMELEN);
2168+ unlock:
2169+ write_unlock_bh(&ip_set_lock);
2170+ return res;
2171+}
2172+
2173+/*
2174+ * Swap two sets so that name/index points to the other.
2175+ * References are also swapped.
2176+ */
2177+static int
2178+ip_set_swap(ip_set_id_t from_index, ip_set_id_t to_index)
2179+{
2180+ struct ip_set *from = ip_set_list[from_index];
2181+ struct ip_set *to = ip_set_list[to_index];
2182+ char from_name[IP_SET_MAXNAMELEN];
2183+ u_int32_t from_ref;
2184+
2185+ DP("set: %s to %s", from->name, to->name);
2186+ /* Features must not change. Artifical restriction. */
2187+ if (from->type->features != to->type->features)
2188+ return -ENOEXEC;
2189+
2190+ /* No magic here: ref munging protected by the mutex */
2191+ write_lock_bh(&ip_set_lock);
2192+ strncpy(from_name, from->name, IP_SET_MAXNAMELEN);
2193+ from_ref = atomic_read(&from->ref);
2194+
2195+ strncpy(from->name, to->name, IP_SET_MAXNAMELEN);
2196+ atomic_set(&from->ref, atomic_read(&to->ref));
2197+ strncpy(to->name, from_name, IP_SET_MAXNAMELEN);
2198+ atomic_set(&to->ref, from_ref);
2199+
2200+ ip_set_list[from_index] = to;
2201+ ip_set_list[to_index] = from;
2202+
2203+ write_unlock_bh(&ip_set_lock);
2204+ return 0;
2205+}
2206+
2207+/*
2208+ * List set data
2209+ */
2210+
2211+static inline void
2212+__set_hash_bindings_size_list(struct ip_set_hash *set_hash,
2213+ ip_set_id_t id, size_t *size)
2214+{
2215+ if (set_hash->id == id)
2216+ *size += sizeof(struct ip_set_hash_list);
2217+}
2218+
2219+static inline void
2220+__set_hash_bindings_size_save(struct ip_set_hash *set_hash,
2221+ ip_set_id_t id, size_t *size)
2222+{
2223+ if (set_hash->id == id)
2224+ *size += sizeof(struct ip_set_hash_save);
2225+}
2226+
2227+static inline void
2228+__set_hash_bindings(struct ip_set_hash *set_hash,
2229+ ip_set_id_t id, void *data, int *used)
2230+{
2231+ if (set_hash->id == id) {
7d2f026e 2232+ struct ip_set_hash_list *hash_list = data + *used;
1aedc22c 2233+
2234+ hash_list->ip = set_hash->ip;
2235+ hash_list->binding = set_hash->binding;
2236+ *used += sizeof(struct ip_set_hash_list);
2237+ }
2238+}
2239+
2240+static int ip_set_list_set(ip_set_id_t index,
2241+ void *data,
2242+ int *used,
2243+ int len)
2244+{
2245+ struct ip_set *set = ip_set_list[index];
2246+ struct ip_set_list *set_list;
2247+
2248+ /* Pointer to our header */
7d2f026e 2249+ set_list = data + *used;
1aedc22c 2250+
2251+ DP("set: %s, used: %d %p %p", set->name, *used, data, data + *used);
2252+
2253+ /* Get and ensure header size */
2254+ if (*used + sizeof(struct ip_set_list) > len)
2255+ goto not_enough_mem;
2256+ *used += sizeof(struct ip_set_list);
2257+
2258+ read_lock_bh(&set->lock);
2259+ /* Get and ensure set specific header size */
2260+ set_list->header_size = set->type->header_size;
2261+ if (*used + set_list->header_size > len)
2262+ goto unlock_set;
2263+
2264+ /* Fill in the header */
2265+ set_list->index = index;
2266+ set_list->binding = set->binding;
2267+ set_list->ref = atomic_read(&set->ref);
2268+
2269+ /* Fill in set spefific header data */
2270+ set->type->list_header(set, data + *used);
2271+ *used += set_list->header_size;
2272+
2273+ /* Get and ensure set specific members size */
2274+ set_list->members_size = set->type->list_members_size(set);
2275+ if (*used + set_list->members_size > len)
2276+ goto unlock_set;
2277+
2278+ /* Fill in set spefific members data */
2279+ set->type->list_members(set, data + *used);
2280+ *used += set_list->members_size;
2281+ read_unlock_bh(&set->lock);
2282+
2283+ /* Bindings */
2284+
2285+ /* Get and ensure set specific bindings size */
2286+ set_list->bindings_size = 0;
2287+ FOREACH_HASH_DO(__set_hash_bindings_size_list,
2288+ set->id, &set_list->bindings_size);
2289+ if (*used + set_list->bindings_size > len)
2290+ goto not_enough_mem;
2291+
2292+ /* Fill in set spefific bindings data */
2293+ FOREACH_HASH_DO(__set_hash_bindings, set->id, data, used);
2294+
2295+ return 0;
2296+
2297+ unlock_set:
2298+ read_unlock_bh(&set->lock);
2299+ not_enough_mem:
2300+ DP("not enough mem, try again");
2301+ return -EAGAIN;
2302+}
2303+
2304+/*
2305+ * Save sets
2306+ */
2307+static int ip_set_save_set(ip_set_id_t index,
2308+ void *data,
2309+ int *used,
2310+ int len)
2311+{
2312+ struct ip_set *set;
2313+ struct ip_set_save *set_save;
2314+
2315+ /* Pointer to our header */
7d2f026e 2316+ set_save = data + *used;
1aedc22c 2317+
2318+ /* Get and ensure header size */
2319+ if (*used + sizeof(struct ip_set_save) > len)
2320+ goto not_enough_mem;
2321+ *used += sizeof(struct ip_set_save);
2322+
2323+ set = ip_set_list[index];
7d2f026e 2324+ DP("set: %s, used: %u(%u) %p %p", set->name, *used, len,
1aedc22c 2325+ data, data + *used);
2326+
2327+ read_lock_bh(&set->lock);
2328+ /* Get and ensure set specific header size */
2329+ set_save->header_size = set->type->header_size;
2330+ if (*used + set_save->header_size > len)
2331+ goto unlock_set;
2332+
2333+ /* Fill in the header */
2334+ set_save->index = index;
2335+ set_save->binding = set->binding;
2336+
2337+ /* Fill in set spefific header data */
2338+ set->type->list_header(set, data + *used);
2339+ *used += set_save->header_size;
2340+
2341+ DP("set header filled: %s, used: %u(%u) %p %p", set->name, *used,
2342+ set_save->header_size, data, data + *used);
2343+ /* Get and ensure set specific members size */
2344+ set_save->members_size = set->type->list_members_size(set);
2345+ if (*used + set_save->members_size > len)
2346+ goto unlock_set;
2347+
2348+ /* Fill in set spefific members data */
2349+ set->type->list_members(set, data + *used);
2350+ *used += set_save->members_size;
2351+ read_unlock_bh(&set->lock);
2352+ DP("set members filled: %s, used: %u(%u) %p %p", set->name, *used,
2353+ set_save->members_size, data, data + *used);
2354+ return 0;
2355+
2356+ unlock_set:
2357+ read_unlock_bh(&set->lock);
2358+ not_enough_mem:
2359+ DP("not enough mem, try again");
2360+ return -EAGAIN;
2361+}
2362+
2363+static inline void
2364+__set_hash_save_bindings(struct ip_set_hash *set_hash,
2365+ ip_set_id_t id,
2366+ void *data,
2367+ int *used,
2368+ int len,
2369+ int *res)
2370+{
2371+ if (*res == 0
2372+ && (id == IP_SET_INVALID_ID || set_hash->id == id)) {
7d2f026e 2373+ struct ip_set_hash_save *hash_save = data + *used;
1aedc22c 2374+ /* Ensure bindings size */
2375+ if (*used + sizeof(struct ip_set_hash_save) > len) {
2376+ *res = -ENOMEM;
2377+ return;
2378+ }
2379+ hash_save->id = set_hash->id;
2380+ hash_save->ip = set_hash->ip;
2381+ hash_save->binding = set_hash->binding;
2382+ *used += sizeof(struct ip_set_hash_save);
2383+ }
2384+}
2385+
2386+static int ip_set_save_bindings(ip_set_id_t index,
2387+ void *data,
2388+ int *used,
2389+ int len)
2390+{
2391+ int res = 0;
2392+ struct ip_set_save *set_save;
2393+
2394+ DP("used %u, len %u", *used, len);
2395+ /* Get and ensure header size */
2396+ if (*used + sizeof(struct ip_set_save) > len)
2397+ return -ENOMEM;
2398+
2399+ /* Marker */
7d2f026e 2400+ set_save = data + *used;
1aedc22c 2401+ set_save->index = IP_SET_INVALID_ID;
2402+ set_save->header_size = 0;
2403+ set_save->members_size = 0;
2404+ *used += sizeof(struct ip_set_save);
2405+
2406+ DP("marker added used %u, len %u", *used, len);
2407+ /* Fill in bindings data */
2408+ if (index != IP_SET_INVALID_ID)
2409+ /* Sets are identified by id in hash */
2410+ index = ip_set_list[index]->id;
2411+ FOREACH_HASH_DO(__set_hash_save_bindings, index, data, used, len, &res);
2412+
2413+ return res;
2414+}
2415+
2416+/*
2417+ * Restore sets
2418+ */
2419+static int ip_set_restore(void *data,
2420+ int len)
2421+{
2422+ int res = 0;
2423+ int line = 0, used = 0, members_size;
2424+ struct ip_set *set;
2425+ struct ip_set_hash_save *hash_save;
2426+ struct ip_set_restore *set_restore;
2427+ ip_set_id_t index;
2428+
2429+ /* Loop to restore sets */
2430+ while (1) {
2431+ line++;
2432+
2433+ DP("%u %u %u", used, sizeof(struct ip_set_restore), len);
2434+ /* Get and ensure header size */
2435+ if (used + sizeof(struct ip_set_restore) > len)
2436+ return line;
7d2f026e 2437+ set_restore = data + used;
1aedc22c 2438+ used += sizeof(struct ip_set_restore);
2439+
2440+ /* Ensure data size */
7d2f026e 2441+ if (used
2442+ + set_restore->header_size
1aedc22c 2443+ + set_restore->members_size > len)
2444+ return line;
2445+
2446+ /* Check marker */
2447+ if (set_restore->index == IP_SET_INVALID_ID) {
2448+ line--;
2449+ goto bindings;
2450+ }
2451+
2452+ /* Try to create the set */
2453+ DP("restore %s %s", set_restore->name, set_restore->typename);
2454+ res = ip_set_create(set_restore->name,
2455+ set_restore->typename,
2456+ set_restore->index,
2457+ data + used,
2458+ set_restore->header_size);
2459+
2460+ if (res != 0)
2461+ return line;
2462+ used += set_restore->header_size;
2463+
2464+ index = ip_set_find_byindex(set_restore->index);
2465+ DP("index %u, restore_index %u", index, set_restore->index);
2466+ if (index != set_restore->index)
2467+ return line;
2468+ /* Try to restore members data */
2469+ set = ip_set_list[index];
2470+ members_size = 0;
2471+ DP("members_size %u reqsize %u",
2472+ set_restore->members_size, set->type->reqsize);
2473+ while (members_size + set->type->reqsize <=
2474+ set_restore->members_size) {
2475+ line++;
2476+ DP("members: %u, line %u", members_size, line);
2477+ res = __ip_set_addip(index,
2478+ data + used + members_size,
2479+ set->type->reqsize);
7d2f026e 2480+ if (!(res == 0 || res == -EEXIST))
1aedc22c 2481+ return line;
2482+ members_size += set->type->reqsize;
2483+ }
2484+
2485+ DP("members_size %u %u",
2486+ set_restore->members_size, members_size);
2487+ if (members_size != set_restore->members_size)
2488+ return line++;
2489+ used += set_restore->members_size;
2490+ }
2491+
2492+ bindings:
2493+ /* Loop to restore bindings */
2494+ while (used < len) {
2495+ line++;
2496+
2497+ DP("restore binding, line %u", line);
2498+ /* Get and ensure size */
2499+ if (used + sizeof(struct ip_set_hash_save) > len)
2500+ return line;
7d2f026e 2501+ hash_save = data + used;
1aedc22c 2502+ used += sizeof(struct ip_set_hash_save);
2503+
2504+ /* hash_save->id is used to store the index */
2505+ index = ip_set_find_byindex(hash_save->id);
2506+ DP("restore binding index %u, id %u, %u -> %u",
2507+ index, hash_save->id, hash_save->ip, hash_save->binding);
2508+ if (index != hash_save->id)
2509+ return line;
9f54053a
JR
2510+ if (ip_set_find_byindex(hash_save->binding) == IP_SET_INVALID_ID) {
2511+ DP("corrupt binding set index %u", hash_save->binding);
2512+ return line;
2513+ }
1aedc22c 2514+ set = ip_set_list[hash_save->id];
2515+ /* Null valued IP means default binding */
2516+ if (hash_save->ip)
7d2f026e 2517+ res = ip_set_hash_add(set->id,
1aedc22c 2518+ hash_save->ip,
2519+ hash_save->binding);
2520+ else {
2521+ IP_SET_ASSERT(set->binding == IP_SET_INVALID_ID);
2522+ write_lock_bh(&ip_set_lock);
2523+ set->binding = hash_save->binding;
2524+ __ip_set_get(set->binding);
2525+ write_unlock_bh(&ip_set_lock);
2526+ DP("default binding: %u", set->binding);
2527+ }
2528+ if (res != 0)
2529+ return line;
2530+ }
2531+ if (used != len)
2532+ return line;
2533+
2534+ return 0;
2535+}
2536+
2537+static int
2538+ip_set_sockfn_set(struct sock *sk, int optval, void *user, unsigned int len)
2539+{
2540+ void *data;
2541+ int res = 0; /* Assume OK */
2542+ unsigned *op;
2543+ struct ip_set_req_adt *req_adt;
2544+ ip_set_id_t index = IP_SET_INVALID_ID;
2545+ int (*adtfn)(ip_set_id_t index,
2546+ const void *data, size_t size);
2547+ struct fn_table {
2548+ int (*fn)(ip_set_id_t index,
2549+ const void *data, size_t size);
2550+ } adtfn_table[] =
2551+ { { ip_set_addip }, { ip_set_delip }, { ip_set_testip},
2552+ { ip_set_bindip}, { ip_set_unbindip }, { ip_set_testbind },
2553+ };
2554+
2555+ DP("optval=%d, user=%p, len=%d", optval, user, len);
2556+ if (!capable(CAP_NET_ADMIN))
2557+ return -EPERM;
2558+ if (optval != SO_IP_SET)
2559+ return -EBADF;
2560+ if (len <= sizeof(unsigned)) {
2561+ ip_set_printk("short userdata (want >%zu, got %u)",
2562+ sizeof(unsigned), len);
2563+ return -EINVAL;
2564+ }
2565+ data = vmalloc(len);
2566+ if (!data) {
2567+ DP("out of mem for %u bytes", len);
2568+ return -ENOMEM;
2569+ }
2570+ if (copy_from_user(data, user, len) != 0) {
2571+ res = -EFAULT;
2572+ goto done;
2573+ }
2574+ if (down_interruptible(&ip_set_app_mutex)) {
2575+ res = -EINTR;
2576+ goto done;
2577+ }
2578+
2579+ op = (unsigned *)data;
2580+ DP("op=%x", *op);
2581+
2582+ if (*op < IP_SET_OP_VERSION) {
2583+ /* Check the version at the beginning of operations */
7d2f026e 2584+ struct ip_set_req_version *req_version = data;
1aedc22c 2585+ if (req_version->version != IP_SET_PROTOCOL_VERSION) {
2586+ res = -EPROTO;
2587+ goto done;
2588+ }
2589+ }
2590+
2591+ switch (*op) {
2592+ case IP_SET_OP_CREATE:{
7d2f026e 2593+ struct ip_set_req_create *req_create = data;
1aedc22c 2594+
2595+ if (len < sizeof(struct ip_set_req_create)) {
2596+ ip_set_printk("short CREATE data (want >=%zu, got %u)",
2597+ sizeof(struct ip_set_req_create), len);
2598+ res = -EINVAL;
2599+ goto done;
2600+ }
2601+ req_create->name[IP_SET_MAXNAMELEN - 1] = '\0';
2602+ req_create->typename[IP_SET_MAXNAMELEN - 1] = '\0';
2603+ res = ip_set_create(req_create->name,
2604+ req_create->typename,
2605+ IP_SET_INVALID_ID,
2606+ data + sizeof(struct ip_set_req_create),
2607+ len - sizeof(struct ip_set_req_create));
2608+ goto done;
2609+ }
2610+ case IP_SET_OP_DESTROY:{
7d2f026e 2611+ struct ip_set_req_std *req_destroy = data;
1aedc22c 2612+
2613+ if (len != sizeof(struct ip_set_req_std)) {
2614+ ip_set_printk("invalid DESTROY data (want %zu, got %u)",
2615+ sizeof(struct ip_set_req_std), len);
2616+ res = -EINVAL;
2617+ goto done;
2618+ }
7d2f026e 2619+ if (SETNAME_EQ(req_destroy->name, IPSET_TOKEN_ALL)) {
1aedc22c 2620+ /* Destroy all sets */
2621+ index = IP_SET_INVALID_ID;
2622+ } else {
2623+ req_destroy->name[IP_SET_MAXNAMELEN - 1] = '\0';
2624+ index = ip_set_find_byname(req_destroy->name);
2625+
2626+ if (index == IP_SET_INVALID_ID) {
2627+ res = -ENOENT;
2628+ goto done;
2629+ }
2630+ }
2631+
2632+ res = ip_set_destroy(index);
2633+ goto done;
2634+ }
2635+ case IP_SET_OP_FLUSH:{
7d2f026e 2636+ struct ip_set_req_std *req_flush = data;
1aedc22c 2637+
2638+ if (len != sizeof(struct ip_set_req_std)) {
2639+ ip_set_printk("invalid FLUSH data (want %zu, got %u)",
2640+ sizeof(struct ip_set_req_std), len);
2641+ res = -EINVAL;
2642+ goto done;
2643+ }
7d2f026e 2644+ if (SETNAME_EQ(req_flush->name, IPSET_TOKEN_ALL)) {
1aedc22c 2645+ /* Flush all sets */
2646+ index = IP_SET_INVALID_ID;
2647+ } else {
2648+ req_flush->name[IP_SET_MAXNAMELEN - 1] = '\0';
2649+ index = ip_set_find_byname(req_flush->name);
2650+
2651+ if (index == IP_SET_INVALID_ID) {
2652+ res = -ENOENT;
2653+ goto done;
2654+ }
2655+ }
2656+ res = ip_set_flush(index);
2657+ goto done;
2658+ }
2659+ case IP_SET_OP_RENAME:{
7d2f026e 2660+ struct ip_set_req_create *req_rename = data;
1aedc22c 2661+
2662+ if (len != sizeof(struct ip_set_req_create)) {
2663+ ip_set_printk("invalid RENAME data (want %zu, got %u)",
2664+ sizeof(struct ip_set_req_create), len);
2665+ res = -EINVAL;
2666+ goto done;
2667+ }
2668+
2669+ req_rename->name[IP_SET_MAXNAMELEN - 1] = '\0';
2670+ req_rename->typename[IP_SET_MAXNAMELEN - 1] = '\0';
2671+
2672+ index = ip_set_find_byname(req_rename->name);
2673+ if (index == IP_SET_INVALID_ID) {
2674+ res = -ENOENT;
2675+ goto done;
2676+ }
2677+ res = ip_set_rename(index, req_rename->typename);
2678+ goto done;
2679+ }
2680+ case IP_SET_OP_SWAP:{
7d2f026e 2681+ struct ip_set_req_create *req_swap = data;
1aedc22c 2682+ ip_set_id_t to_index;
2683+
2684+ if (len != sizeof(struct ip_set_req_create)) {
2685+ ip_set_printk("invalid SWAP data (want %zu, got %u)",
2686+ sizeof(struct ip_set_req_create), len);
2687+ res = -EINVAL;
2688+ goto done;
2689+ }
2690+
2691+ req_swap->name[IP_SET_MAXNAMELEN - 1] = '\0';
2692+ req_swap->typename[IP_SET_MAXNAMELEN - 1] = '\0';
2693+
2694+ index = ip_set_find_byname(req_swap->name);
2695+ if (index == IP_SET_INVALID_ID) {
2696+ res = -ENOENT;
2697+ goto done;
2698+ }
2699+ to_index = ip_set_find_byname(req_swap->typename);
2700+ if (to_index == IP_SET_INVALID_ID) {
2701+ res = -ENOENT;
2702+ goto done;
2703+ }
2704+ res = ip_set_swap(index, to_index);
2705+ goto done;
2706+ }
7d2f026e 2707+ default:
1aedc22c 2708+ break; /* Set identified by id */
2709+ }
2710+
2711+ /* There we may have add/del/test/bind/unbind/test_bind operations */
2712+ if (*op < IP_SET_OP_ADD_IP || *op > IP_SET_OP_TEST_BIND_SET) {
2713+ res = -EBADMSG;
2714+ goto done;
2715+ }
2716+ adtfn = adtfn_table[*op - IP_SET_OP_ADD_IP].fn;
2717+
2718+ if (len < sizeof(struct ip_set_req_adt)) {
2719+ ip_set_printk("short data in adt request (want >=%zu, got %u)",
2720+ sizeof(struct ip_set_req_adt), len);
2721+ res = -EINVAL;
2722+ goto done;
2723+ }
7d2f026e 2724+ req_adt = data;
1aedc22c 2725+
2726+ /* -U :all: :all:|:default: uses IP_SET_INVALID_ID */
7d2f026e 2727+ if (!(*op == IP_SET_OP_UNBIND_SET
1aedc22c 2728+ && req_adt->index == IP_SET_INVALID_ID)) {
2729+ index = ip_set_find_byindex(req_adt->index);
2730+ if (index == IP_SET_INVALID_ID) {
2731+ res = -ENOENT;
2732+ goto done;
2733+ }
2734+ }
2735+ res = adtfn(index, data, len);
2736+
2737+ done:
2738+ up(&ip_set_app_mutex);
2739+ vfree(data);
2740+ if (res > 0)
2741+ res = 0;
2742+ DP("final result %d", res);
2743+ return res;
2744+}
2745+
7d2f026e 2746+static int
1aedc22c 2747+ip_set_sockfn_get(struct sock *sk, int optval, void *user, int *len)
2748+{
2749+ int res = 0;
2750+ unsigned *op;
2751+ ip_set_id_t index = IP_SET_INVALID_ID;
2752+ void *data;
2753+ int copylen = *len;
2754+
2755+ DP("optval=%d, user=%p, len=%d", optval, user, *len);
2756+ if (!capable(CAP_NET_ADMIN))
2757+ return -EPERM;
2758+ if (optval != SO_IP_SET)
2759+ return -EBADF;
2760+ if (*len < sizeof(unsigned)) {
2761+ ip_set_printk("short userdata (want >=%zu, got %d)",
2762+ sizeof(unsigned), *len);
2763+ return -EINVAL;
2764+ }
2765+ data = vmalloc(*len);
2766+ if (!data) {
2767+ DP("out of mem for %d bytes", *len);
2768+ return -ENOMEM;
2769+ }
2770+ if (copy_from_user(data, user, *len) != 0) {
2771+ res = -EFAULT;
2772+ goto done;
2773+ }
2774+ if (down_interruptible(&ip_set_app_mutex)) {
2775+ res = -EINTR;
2776+ goto done;
2777+ }
2778+
2779+ op = (unsigned *) data;
2780+ DP("op=%x", *op);
2781+
2782+ if (*op < IP_SET_OP_VERSION) {
2783+ /* Check the version at the beginning of operations */
7d2f026e 2784+ struct ip_set_req_version *req_version = data;
1aedc22c 2785+ if (req_version->version != IP_SET_PROTOCOL_VERSION) {
2786+ res = -EPROTO;
2787+ goto done;
2788+ }
2789+ }
2790+
2791+ switch (*op) {
2792+ case IP_SET_OP_VERSION: {
7d2f026e 2793+ struct ip_set_req_version *req_version = data;
1aedc22c 2794+
2795+ if (*len != sizeof(struct ip_set_req_version)) {
2796+ ip_set_printk("invalid VERSION (want %zu, got %d)",
2797+ sizeof(struct ip_set_req_version),
2798+ *len);
2799+ res = -EINVAL;
2800+ goto done;
2801+ }
2802+
2803+ req_version->version = IP_SET_PROTOCOL_VERSION;
2804+ res = copy_to_user(user, req_version,
2805+ sizeof(struct ip_set_req_version));
2806+ goto done;
2807+ }
2808+ case IP_SET_OP_GET_BYNAME: {
7d2f026e 2809+ struct ip_set_req_get_set *req_get = data;
1aedc22c 2810+
2811+ if (*len != sizeof(struct ip_set_req_get_set)) {
2812+ ip_set_printk("invalid GET_BYNAME (want %zu, got %d)",
2813+ sizeof(struct ip_set_req_get_set), *len);
2814+ res = -EINVAL;
2815+ goto done;
2816+ }
2817+ req_get->set.name[IP_SET_MAXNAMELEN - 1] = '\0';
2818+ index = ip_set_find_byname(req_get->set.name);
2819+ req_get->set.index = index;
2820+ goto copy;
2821+ }
2822+ case IP_SET_OP_GET_BYINDEX: {
7d2f026e 2823+ struct ip_set_req_get_set *req_get = data;
1aedc22c 2824+
2825+ if (*len != sizeof(struct ip_set_req_get_set)) {
2826+ ip_set_printk("invalid GET_BYINDEX (want %zu, got %d)",
2827+ sizeof(struct ip_set_req_get_set), *len);
2828+ res = -EINVAL;
2829+ goto done;
2830+ }
2831+ req_get->set.name[IP_SET_MAXNAMELEN - 1] = '\0';
2832+ index = ip_set_find_byindex(req_get->set.index);
2833+ strncpy(req_get->set.name,
2834+ index == IP_SET_INVALID_ID ? ""
2835+ : ip_set_list[index]->name, IP_SET_MAXNAMELEN);
2836+ goto copy;
2837+ }
2838+ case IP_SET_OP_ADT_GET: {
7d2f026e 2839+ struct ip_set_req_adt_get *req_get = data;
1aedc22c 2840+
2841+ if (*len != sizeof(struct ip_set_req_adt_get)) {
2842+ ip_set_printk("invalid ADT_GET (want %zu, got %d)",
2843+ sizeof(struct ip_set_req_adt_get), *len);
2844+ res = -EINVAL;
2845+ goto done;
2846+ }
2847+ req_get->set.name[IP_SET_MAXNAMELEN - 1] = '\0';
2848+ index = ip_set_find_byname(req_get->set.name);
2849+ if (index != IP_SET_INVALID_ID) {
2850+ req_get->set.index = index;
2851+ strncpy(req_get->typename,
2852+ ip_set_list[index]->type->typename,
2853+ IP_SET_MAXNAMELEN - 1);
2854+ } else {
2855+ res = -ENOENT;
2856+ goto done;
2857+ }
2858+ goto copy;
2859+ }
2860+ case IP_SET_OP_MAX_SETS: {
7d2f026e 2861+ struct ip_set_req_max_sets *req_max_sets = data;
1aedc22c 2862+ ip_set_id_t i;
2863+
2864+ if (*len != sizeof(struct ip_set_req_max_sets)) {
2865+ ip_set_printk("invalid MAX_SETS (want %zu, got %d)",
2866+ sizeof(struct ip_set_req_max_sets), *len);
2867+ res = -EINVAL;
2868+ goto done;
2869+ }
2870+
7d2f026e 2871+ if (SETNAME_EQ(req_max_sets->set.name, IPSET_TOKEN_ALL)) {
1aedc22c 2872+ req_max_sets->set.index = IP_SET_INVALID_ID;
2873+ } else {
2874+ req_max_sets->set.name[IP_SET_MAXNAMELEN - 1] = '\0';
7d2f026e 2875+ req_max_sets->set.index =
1aedc22c 2876+ ip_set_find_byname(req_max_sets->set.name);
2877+ if (req_max_sets->set.index == IP_SET_INVALID_ID) {
2878+ res = -ENOENT;
2879+ goto done;
2880+ }
2881+ }
2882+ req_max_sets->max_sets = ip_set_max;
2883+ req_max_sets->sets = 0;
2884+ for (i = 0; i < ip_set_max; i++) {
2885+ if (ip_set_list[i] != NULL)
2886+ req_max_sets->sets++;
2887+ }
2888+ goto copy;
2889+ }
7d2f026e 2890+ case IP_SET_OP_LIST_SIZE:
1aedc22c 2891+ case IP_SET_OP_SAVE_SIZE: {
7d2f026e 2892+ struct ip_set_req_setnames *req_setnames = data;
1aedc22c 2893+ struct ip_set_name_list *name_list;
2894+ struct ip_set *set;
2895+ ip_set_id_t i;
2896+ int used;
2897+
2898+ if (*len < sizeof(struct ip_set_req_setnames)) {
2899+ ip_set_printk("short LIST_SIZE (want >=%zu, got %d)",
2900+ sizeof(struct ip_set_req_setnames), *len);
2901+ res = -EINVAL;
2902+ goto done;
2903+ }
2904+
2905+ req_setnames->size = 0;
2906+ used = sizeof(struct ip_set_req_setnames);
2907+ for (i = 0; i < ip_set_max; i++) {
2908+ if (ip_set_list[i] == NULL)
2909+ continue;
7d2f026e 2910+ name_list = data + used;
1aedc22c 2911+ used += sizeof(struct ip_set_name_list);
2912+ if (used > copylen) {
2913+ res = -EAGAIN;
2914+ goto done;
2915+ }
2916+ set = ip_set_list[i];
2917+ /* Fill in index, name, etc. */
2918+ name_list->index = i;
2919+ name_list->id = set->id;
2920+ strncpy(name_list->name,
2921+ set->name,
2922+ IP_SET_MAXNAMELEN - 1);
2923+ strncpy(name_list->typename,
2924+ set->type->typename,
2925+ IP_SET_MAXNAMELEN - 1);
2926+ DP("filled %s of type %s, index %u\n",
2927+ name_list->name, name_list->typename,
2928+ name_list->index);
2929+ if (!(req_setnames->index == IP_SET_INVALID_ID
2930+ || req_setnames->index == i))
2931+ continue;
2932+ /* Update size */
2933+ switch (*op) {
2934+ case IP_SET_OP_LIST_SIZE: {
2935+ req_setnames->size += sizeof(struct ip_set_list)
2936+ + set->type->header_size
2937+ + set->type->list_members_size(set);
2938+ /* Sets are identified by id in the hash */
7d2f026e 2939+ FOREACH_HASH_DO(__set_hash_bindings_size_list,
1aedc22c 2940+ set->id, &req_setnames->size);
2941+ break;
2942+ }
2943+ case IP_SET_OP_SAVE_SIZE: {
2944+ req_setnames->size += sizeof(struct ip_set_save)
2945+ + set->type->header_size
2946+ + set->type->list_members_size(set);
2947+ FOREACH_HASH_DO(__set_hash_bindings_size_save,
2948+ set->id, &req_setnames->size);
2949+ break;
2950+ }
2951+ default:
2952+ break;
2953+ }
2954+ }
2955+ if (copylen != used) {
2956+ res = -EAGAIN;
2957+ goto done;
2958+ }
2959+ goto copy;
2960+ }
2961+ case IP_SET_OP_LIST: {
7d2f026e 2962+ struct ip_set_req_list *req_list = data;
1aedc22c 2963+ ip_set_id_t i;
2964+ int used;
2965+
2966+ if (*len < sizeof(struct ip_set_req_list)) {
2967+ ip_set_printk("short LIST (want >=%zu, got %d)",
2968+ sizeof(struct ip_set_req_list), *len);
2969+ res = -EINVAL;
2970+ goto done;
2971+ }
2972+ index = req_list->index;
2973+ if (index != IP_SET_INVALID_ID
2974+ && ip_set_find_byindex(index) != index) {
2975+ res = -ENOENT;
2976+ goto done;
2977+ }
2978+ used = 0;
2979+ if (index == IP_SET_INVALID_ID) {
2980+ /* List all sets */
2981+ for (i = 0; i < ip_set_max && res == 0; i++) {
2982+ if (ip_set_list[i] != NULL)
2983+ res = ip_set_list_set(i, data, &used, *len);
2984+ }
2985+ } else {
2986+ /* List an individual set */
2987+ res = ip_set_list_set(index, data, &used, *len);
2988+ }
2989+ if (res != 0)
2990+ goto done;
2991+ else if (copylen != used) {
2992+ res = -EAGAIN;
2993+ goto done;
2994+ }
2995+ goto copy;
2996+ }
2997+ case IP_SET_OP_SAVE: {
7d2f026e 2998+ struct ip_set_req_list *req_save = data;
1aedc22c 2999+ ip_set_id_t i;
3000+ int used;
3001+
3002+ if (*len < sizeof(struct ip_set_req_list)) {
3003+ ip_set_printk("short SAVE (want >=%zu, got %d)",
3004+ sizeof(struct ip_set_req_list), *len);
3005+ res = -EINVAL;
3006+ goto done;
3007+ }
3008+ index = req_save->index;
3009+ if (index != IP_SET_INVALID_ID
3010+ && ip_set_find_byindex(index) != index) {
3011+ res = -ENOENT;
3012+ goto done;
3013+ }
3014+ used = 0;
3015+ if (index == IP_SET_INVALID_ID) {
3016+ /* Save all sets */
3017+ for (i = 0; i < ip_set_max && res == 0; i++) {
3018+ if (ip_set_list[i] != NULL)
3019+ res = ip_set_save_set(i, data, &used, *len);
3020+ }
3021+ } else {
3022+ /* Save an individual set */
3023+ res = ip_set_save_set(index, data, &used, *len);
3024+ }
3025+ if (res == 0)
3026+ res = ip_set_save_bindings(index, data, &used, *len);
3027+
3028+ if (res != 0)
3029+ goto done;
3030+ else if (copylen != used) {
3031+ res = -EAGAIN;
3032+ goto done;
3033+ }
3034+ goto copy;
3035+ }
3036+ case IP_SET_OP_RESTORE: {
7d2f026e 3037+ struct ip_set_req_setnames *req_restore = data;
1aedc22c 3038+ int line;
3039+
3040+ if (*len < sizeof(struct ip_set_req_setnames)
3041+ || *len != req_restore->size) {
3042+ ip_set_printk("invalid RESTORE (want =%zu, got %d)",
3043+ req_restore->size, *len);
3044+ res = -EINVAL;
3045+ goto done;
3046+ }
3047+ line = ip_set_restore(data + sizeof(struct ip_set_req_setnames),
3048+ req_restore->size - sizeof(struct ip_set_req_setnames));
3049+ DP("ip_set_restore: %u", line);
3050+ if (line != 0) {
3051+ res = -EAGAIN;
3052+ req_restore->size = line;
3053+ copylen = sizeof(struct ip_set_req_setnames);
3054+ goto copy;
3055+ }
3056+ goto done;
3057+ }
3058+ default:
3059+ res = -EBADMSG;
3060+ goto done;
3061+ } /* end of switch(op) */
3062+
3063+ copy:
3064+ DP("set %s, copylen %u", index != IP_SET_INVALID_ID
3065+ && ip_set_list[index]
3066+ ? ip_set_list[index]->name
3067+ : ":all:", copylen);
3068+ res = copy_to_user(user, data, copylen);
3069+
3070+ done:
3071+ up(&ip_set_app_mutex);
3072+ vfree(data);
3073+ if (res > 0)
3074+ res = 0;
3075+ DP("final result %d", res);
3076+ return res;
3077+}
3078+
3079+static struct nf_sockopt_ops so_set = {
3080+ .pf = PF_INET,
3081+ .set_optmin = SO_IP_SET,
3082+ .set_optmax = SO_IP_SET + 1,
3083+ .set = &ip_set_sockfn_set,
3084+ .get_optmin = SO_IP_SET,
3085+ .get_optmax = SO_IP_SET + 1,
7d2f026e 3086+ .get = &ip_set_sockfn_get,
3087+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23)
3088+ .use = 0,
3089+#else
3090+ .owner = THIS_MODULE,
3091+#endif
1aedc22c 3092+};
3093+
3094+static int max_sets, hash_size;
3095+module_param(max_sets, int, 0600);
3096+MODULE_PARM_DESC(max_sets, "maximal number of sets");
3097+module_param(hash_size, int, 0600);
3098+MODULE_PARM_DESC(hash_size, "hash size for bindings");
3099+MODULE_LICENSE("GPL");
3100+MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
3101+MODULE_DESCRIPTION("module implementing core IP set support");
3102+
f45e9687 3103+static int __init ip_set_init(void)
1aedc22c 3104+{
3105+ int res;
3106+ ip_set_id_t i;
3107+
3108+ get_random_bytes(&ip_set_hash_random, 4);
3109+ if (max_sets)
3110+ ip_set_max = max_sets;
3111+ ip_set_list = vmalloc(sizeof(struct ip_set *) * ip_set_max);
3112+ if (!ip_set_list) {
3113+ printk(KERN_ERR "Unable to create ip_set_list\n");
3114+ return -ENOMEM;
3115+ }
3116+ memset(ip_set_list, 0, sizeof(struct ip_set *) * ip_set_max);
3117+ if (hash_size)
3118+ ip_set_bindings_hash_size = hash_size;
3119+ ip_set_hash = vmalloc(sizeof(struct list_head) * ip_set_bindings_hash_size);
3120+ if (!ip_set_hash) {
3121+ printk(KERN_ERR "Unable to create ip_set_hash\n");
3122+ vfree(ip_set_list);
3123+ return -ENOMEM;
3124+ }
3125+ for (i = 0; i < ip_set_bindings_hash_size; i++)
3126+ INIT_LIST_HEAD(&ip_set_hash[i]);
3127+
3128+ INIT_LIST_HEAD(&set_type_list);
3129+
3130+ res = nf_register_sockopt(&so_set);
3131+ if (res != 0) {
3132+ ip_set_printk("SO_SET registry failed: %d", res);
3133+ vfree(ip_set_list);
3134+ vfree(ip_set_hash);
3135+ return res;
3136+ }
3137+ return 0;
3138+}
3139+
f45e9687 3140+static void __exit ip_set_fini(void)
1aedc22c 3141+{
3142+ /* There can't be any existing set or binding */
3143+ nf_unregister_sockopt(&so_set);
3144+ vfree(ip_set_list);
3145+ vfree(ip_set_hash);
3146+ DP("these are the famous last words");
3147+}
3148+
3149+EXPORT_SYMBOL(ip_set_register_set_type);
3150+EXPORT_SYMBOL(ip_set_unregister_set_type);
3151+
3152+EXPORT_SYMBOL(ip_set_get_byname);
3153+EXPORT_SYMBOL(ip_set_get_byindex);
3154+EXPORT_SYMBOL(ip_set_put);
3155+
3156+EXPORT_SYMBOL(ip_set_addip_kernel);
3157+EXPORT_SYMBOL(ip_set_delip_kernel);
3158+EXPORT_SYMBOL(ip_set_testip_kernel);
3159+
f45e9687 3160+module_init(ip_set_init);
3161+module_exit(ip_set_fini);
7d2f026e 3162diff -uNrp --exclude=.svn a/net/ipv4/netfilter/ip_set_iphash.c linux-2.6/net/ipv4/netfilter/ip_set_iphash.c
3163--- a/net/ipv4/netfilter/ip_set_iphash.c 1970-01-01 01:00:00.000000000 +0100
3164+++ linux-2.6/net/ipv4/netfilter/ip_set_iphash.c 2008-07-08 16:52:53.965201208 +0200
3165@@ -0,0 +1,425 @@
1aedc22c 3166+/* Copyright (C) 2003-2004 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
3167+ *
3168+ * This program is free software; you can redistribute it and/or modify
3169+ * it under the terms of the GNU General Public License version 2 as
7d2f026e 3170+ * published by the Free Software Foundation.
1aedc22c 3171+ */
3172+
3173+/* Kernel module implementing an ip hash set */
3174+
3175+#include <linux/module.h>
3176+#include <linux/ip.h>
3177+#include <linux/skbuff.h>
f45e9687 3178+#include <linux/version.h>
3179+#include <linux/jhash.h>
1aedc22c 3180+#include <linux/netfilter_ipv4/ip_tables.h>
3181+#include <linux/netfilter_ipv4/ip_set.h>
3182+#include <linux/errno.h>
3183+#include <asm/uaccess.h>
3184+#include <asm/bitops.h>
3185+#include <linux/spinlock.h>
3186+#include <linux/vmalloc.h>
3187+#include <linux/random.h>
3188+
3189+#include <net/ip.h>
3190+
3191+#include <linux/netfilter_ipv4/ip_set_malloc.h>
3192+#include <linux/netfilter_ipv4/ip_set_iphash.h>
1aedc22c 3193+
3194+static int limit = MAX_RANGE;
3195+
3196+static inline __u32
3197+jhash_ip(const struct ip_set_iphash *map, uint16_t i, ip_set_ip_t ip)
3198+{
3199+ return jhash_1word(ip, *(((uint32_t *) map->initval) + i));
3200+}
3201+
3202+static inline __u32
3203+hash_id(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip)
3204+{
7d2f026e 3205+ struct ip_set_iphash *map = set->data;
1aedc22c 3206+ __u32 id;
3207+ u_int16_t i;
3208+ ip_set_ip_t *elem;
3209+
3210+ *hash_ip = ip & map->netmask;
3211+ DP("set: %s, ip:%u.%u.%u.%u, %u.%u.%u.%u, %u.%u.%u.%u",
3212+ set->name, HIPQUAD(ip), HIPQUAD(*hash_ip), HIPQUAD(map->netmask));
3213+
3214+ for (i = 0; i < map->probes; i++) {
3215+ id = jhash_ip(map, i, *hash_ip) % map->hashsize;
3216+ DP("hash key: %u", id);
3217+ elem = HARRAY_ELEM(map->members, ip_set_ip_t *, id);
3218+ if (*elem == *hash_ip)
3219+ return id;
3220+ /* No shortcut at testing - there can be deleted
3221+ * entries. */
3222+ }
3223+ return UINT_MAX;
3224+}
3225+
3226+static inline int
3227+__testip(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip)
3228+{
3229+ return (ip && hash_id(set, ip, hash_ip) != UINT_MAX);
3230+}
3231+
3232+static int
3233+testip(struct ip_set *set, const void *data, size_t size,
3234+ ip_set_ip_t *hash_ip)
3235+{
7d2f026e 3236+ const struct ip_set_req_iphash *req = data;
1aedc22c 3237+
3238+ if (size != sizeof(struct ip_set_req_iphash)) {
3239+ ip_set_printk("data length wrong (want %zu, have %zu)",
3240+ sizeof(struct ip_set_req_iphash),
3241+ size);
3242+ return -EINVAL;
3243+ }
3244+ return __testip(set, req->ip, hash_ip);
3245+}
3246+
3247+static int
7d2f026e 3248+testip_kernel(struct ip_set *set,
1aedc22c 3249+ const struct sk_buff *skb,
3250+ ip_set_ip_t *hash_ip,
3251+ const u_int32_t *flags,
3252+ unsigned char index)
3253+{
3254+ return __testip(set,
7d2f026e 3255+ ntohl(flags[index] & IPSET_SRC
f45e9687 3256+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
7d2f026e 3257+ ? ip_hdr(skb)->saddr
5ce52adc 3258+ : ip_hdr(skb)->daddr),
f45e9687 3259+#else
7d2f026e 3260+ ? skb->nh.iph->saddr
f45e9687 3261+ : skb->nh.iph->daddr),
3262+#endif
1aedc22c 3263+ hash_ip);
3264+}
3265+
3266+static inline int
3267+__addip(struct ip_set_iphash *map, ip_set_ip_t ip, ip_set_ip_t *hash_ip)
3268+{
3269+ __u32 probe;
3270+ u_int16_t i;
3271+ ip_set_ip_t *elem;
3272+
f45e9687 3273+ if (!ip || map->elements >= limit)
1aedc22c 3274+ return -ERANGE;
3275+
3276+ *hash_ip = ip & map->netmask;
3277+
3278+ for (i = 0; i < map->probes; i++) {
3279+ probe = jhash_ip(map, i, *hash_ip) % map->hashsize;
3280+ elem = HARRAY_ELEM(map->members, ip_set_ip_t *, probe);
3281+ if (*elem == *hash_ip)
3282+ return -EEXIST;
3283+ if (!*elem) {
3284+ *elem = *hash_ip;
3285+ map->elements++;
3286+ return 0;
3287+ }
3288+ }
3289+ /* Trigger rehashing */
3290+ return -EAGAIN;
3291+}
3292+
3293+static int
3294+addip(struct ip_set *set, const void *data, size_t size,
3295+ ip_set_ip_t *hash_ip)
3296+{
7d2f026e 3297+ const struct ip_set_req_iphash *req = data;
1aedc22c 3298+
3299+ if (size != sizeof(struct ip_set_req_iphash)) {
3300+ ip_set_printk("data length wrong (want %zu, have %zu)",
3301+ sizeof(struct ip_set_req_iphash),
3302+ size);
3303+ return -EINVAL;
3304+ }
7d2f026e 3305+ return __addip(set->data, req->ip, hash_ip);
1aedc22c 3306+}
3307+
3308+static int
7d2f026e 3309+addip_kernel(struct ip_set *set,
1aedc22c 3310+ const struct sk_buff *skb,
3311+ ip_set_ip_t *hash_ip,
3312+ const u_int32_t *flags,
3313+ unsigned char index)
3314+{
3315+ return __addip((struct ip_set_iphash *) set->data,
7d2f026e 3316+ ntohl(flags[index] & IPSET_SRC
f45e9687 3317+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
7d2f026e 3318+ ? ip_hdr(skb)->saddr
5ce52adc 3319+ : ip_hdr(skb)->daddr),
f45e9687 3320+#else
7d2f026e 3321+ ? skb->nh.iph->saddr
f45e9687 3322+ : skb->nh.iph->daddr),
3323+#endif
1aedc22c 3324+ hash_ip);
3325+}
3326+
3327+static int retry(struct ip_set *set)
3328+{
7d2f026e 3329+ struct ip_set_iphash *map = set->data;
1aedc22c 3330+ ip_set_ip_t hash_ip, *elem;
3331+ void *members;
3332+ u_int32_t i, hashsize = map->hashsize;
3333+ int res;
3334+ struct ip_set_iphash *tmp;
3335+
3336+ if (map->resize == 0)
3337+ return -ERANGE;
3338+
3339+ again:
3340+ res = 0;
3341+
3342+ /* Calculate new hash size */
3343+ hashsize += (hashsize * map->resize)/100;
3344+ if (hashsize == map->hashsize)
3345+ hashsize++;
3346+
3347+ ip_set_printk("rehashing of set %s triggered: "
3348+ "hashsize grows from %u to %u",
3349+ set->name, map->hashsize, hashsize);
3350+
7d2f026e 3351+ tmp = kmalloc(sizeof(struct ip_set_iphash)
1aedc22c 3352+ + map->probes * sizeof(uint32_t), GFP_ATOMIC);
3353+ if (!tmp) {
3354+ DP("out of memory for %d bytes",
3355+ sizeof(struct ip_set_iphash)
3356+ + map->probes * sizeof(uint32_t));
3357+ return -ENOMEM;
3358+ }
3359+ tmp->members = harray_malloc(hashsize, sizeof(ip_set_ip_t), GFP_ATOMIC);
3360+ if (!tmp->members) {
3361+ DP("out of memory for %d bytes", hashsize * sizeof(ip_set_ip_t));
3362+ kfree(tmp);
3363+ return -ENOMEM;
3364+ }
3365+ tmp->hashsize = hashsize;
3366+ tmp->elements = 0;
3367+ tmp->probes = map->probes;
3368+ tmp->resize = map->resize;
3369+ tmp->netmask = map->netmask;
3370+ memcpy(tmp->initval, map->initval, map->probes * sizeof(uint32_t));
3371+
3372+ write_lock_bh(&set->lock);
7d2f026e 3373+ map = set->data; /* Play safe */
1aedc22c 3374+ for (i = 0; i < map->hashsize && res == 0; i++) {
3375+ elem = HARRAY_ELEM(map->members, ip_set_ip_t *, i);
3376+ if (*elem)
3377+ res = __addip(tmp, *elem, &hash_ip);
3378+ }
3379+ if (res) {
3380+ /* Failure, try again */
3381+ write_unlock_bh(&set->lock);
3382+ harray_free(tmp->members);
3383+ kfree(tmp);
3384+ goto again;
3385+ }
3386+
3387+ /* Success at resizing! */
3388+ members = map->members;
3389+
3390+ map->hashsize = tmp->hashsize;
3391+ map->members = tmp->members;
3392+ write_unlock_bh(&set->lock);
3393+
3394+ harray_free(members);
3395+ kfree(tmp);
3396+
3397+ return 0;
3398+}
3399+
3400+static inline int
3401+__delip(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip)
3402+{
7d2f026e 3403+ struct ip_set_iphash *map = set->data;
1aedc22c 3404+ ip_set_ip_t id, *elem;
3405+
3406+ if (!ip)
3407+ return -ERANGE;
3408+
3409+ id = hash_id(set, ip, hash_ip);
3410+ if (id == UINT_MAX)
3411+ return -EEXIST;
3412+
3413+ elem = HARRAY_ELEM(map->members, ip_set_ip_t *, id);
3414+ *elem = 0;
3415+ map->elements--;
3416+
3417+ return 0;
3418+}
3419+
3420+static int
3421+delip(struct ip_set *set, const void *data, size_t size,
3422+ ip_set_ip_t *hash_ip)
3423+{
7d2f026e 3424+ const struct ip_set_req_iphash *req = data;
1aedc22c 3425+
3426+ if (size != sizeof(struct ip_set_req_iphash)) {
3427+ ip_set_printk("data length wrong (want %zu, have %zu)",
3428+ sizeof(struct ip_set_req_iphash),
3429+ size);
3430+ return -EINVAL;
3431+ }
3432+ return __delip(set, req->ip, hash_ip);
3433+}
3434+
3435+static int
7d2f026e 3436+delip_kernel(struct ip_set *set,
1aedc22c 3437+ const struct sk_buff *skb,
3438+ ip_set_ip_t *hash_ip,
3439+ const u_int32_t *flags,
3440+ unsigned char index)
3441+{
3442+ return __delip(set,
7d2f026e 3443+ ntohl(flags[index] & IPSET_SRC
f45e9687 3444+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
7d2f026e 3445+ ? ip_hdr(skb)->saddr
5ce52adc 3446+ : ip_hdr(skb)->daddr),
f45e9687 3447+#else
7d2f026e 3448+ ? skb->nh.iph->saddr
f45e9687 3449+ : skb->nh.iph->daddr),
3450+#endif
1aedc22c 3451+ hash_ip);
3452+}
3453+
3454+static int create(struct ip_set *set, const void *data, size_t size)
3455+{
7d2f026e 3456+ const struct ip_set_req_iphash_create *req = data;
1aedc22c 3457+ struct ip_set_iphash *map;
3458+ uint16_t i;
3459+
3460+ if (size != sizeof(struct ip_set_req_iphash_create)) {
3461+ ip_set_printk("data length wrong (want %zu, have %zu)",
3462+ sizeof(struct ip_set_req_iphash_create),
3463+ size);
3464+ return -EINVAL;
3465+ }
3466+
3467+ if (req->hashsize < 1) {
3468+ ip_set_printk("hashsize too small");
3469+ return -ENOEXEC;
3470+ }
3471+
3472+ if (req->probes < 1) {
3473+ ip_set_printk("probes too small");
3474+ return -ENOEXEC;
3475+ }
3476+
7d2f026e 3477+ map = kmalloc(sizeof(struct ip_set_iphash)
1aedc22c 3478+ + req->probes * sizeof(uint32_t), GFP_KERNEL);
3479+ if (!map) {
3480+ DP("out of memory for %d bytes",
3481+ sizeof(struct ip_set_iphash)
3482+ + req->probes * sizeof(uint32_t));
3483+ return -ENOMEM;
3484+ }
3485+ for (i = 0; i < req->probes; i++)
3486+ get_random_bytes(((uint32_t *) map->initval)+i, 4);
3487+ map->elements = 0;
3488+ map->hashsize = req->hashsize;
3489+ map->probes = req->probes;
3490+ map->resize = req->resize;
3491+ map->netmask = req->netmask;
3492+ map->members = harray_malloc(map->hashsize, sizeof(ip_set_ip_t), GFP_KERNEL);
3493+ if (!map->members) {
3494+ DP("out of memory for %d bytes", map->hashsize * sizeof(ip_set_ip_t));
3495+ kfree(map);
3496+ return -ENOMEM;
3497+ }
3498+
3499+ set->data = map;
3500+ return 0;
3501+}
3502+
3503+static void destroy(struct ip_set *set)
3504+{
7d2f026e 3505+ struct ip_set_iphash *map = set->data;
1aedc22c 3506+
3507+ harray_free(map->members);
3508+ kfree(map);
3509+
3510+ set->data = NULL;
3511+}
3512+
3513+static void flush(struct ip_set *set)
3514+{
7d2f026e 3515+ struct ip_set_iphash *map = set->data;
1aedc22c 3516+ harray_flush(map->members, map->hashsize, sizeof(ip_set_ip_t));
3517+ map->elements = 0;
3518+}
3519+
3520+static void list_header(const struct ip_set *set, void *data)
3521+{
7d2f026e 3522+ struct ip_set_iphash *map = set->data;
3523+ struct ip_set_req_iphash_create *header = data;
1aedc22c 3524+
3525+ header->hashsize = map->hashsize;
3526+ header->probes = map->probes;
3527+ header->resize = map->resize;
3528+ header->netmask = map->netmask;
3529+}
3530+
3531+static int list_members_size(const struct ip_set *set)
3532+{
7d2f026e 3533+ const struct ip_set_iphash *map = set->data;
1aedc22c 3534+
3535+ return (map->hashsize * sizeof(ip_set_ip_t));
3536+}
3537+
3538+static void list_members(const struct ip_set *set, void *data)
3539+{
7d2f026e 3540+ const struct ip_set_iphash *map = set->data;
1aedc22c 3541+ ip_set_ip_t i, *elem;
3542+
3543+ for (i = 0; i < map->hashsize; i++) {
3544+ elem = HARRAY_ELEM(map->members, ip_set_ip_t *, i);
3545+ ((ip_set_ip_t *)data)[i] = *elem;
3546+ }
3547+}
3548+
3549+static struct ip_set_type ip_set_iphash = {
3550+ .typename = SETTYPE_NAME,
3551+ .features = IPSET_TYPE_IP | IPSET_DATA_SINGLE,
3552+ .protocol_version = IP_SET_PROTOCOL_VERSION,
3553+ .create = &create,
3554+ .destroy = &destroy,
3555+ .flush = &flush,
3556+ .reqsize = sizeof(struct ip_set_req_iphash),
3557+ .addip = &addip,
3558+ .addip_kernel = &addip_kernel,
3559+ .retry = &retry,
3560+ .delip = &delip,
3561+ .delip_kernel = &delip_kernel,
3562+ .testip = &testip,
3563+ .testip_kernel = &testip_kernel,
3564+ .header_size = sizeof(struct ip_set_req_iphash_create),
3565+ .list_header = &list_header,
3566+ .list_members_size = &list_members_size,
3567+ .list_members = &list_members,
3568+ .me = THIS_MODULE,
3569+};
3570+
3571+MODULE_LICENSE("GPL");
3572+MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
3573+MODULE_DESCRIPTION("iphash type of IP sets");
3574+module_param(limit, int, 0600);
3575+MODULE_PARM_DESC(limit, "maximal number of elements stored in the sets");
3576+
f45e9687 3577+static int __init ip_set_iphash_init(void)
1aedc22c 3578+{
7d2f026e 3579+ init_max_page_size();
1aedc22c 3580+ return ip_set_register_set_type(&ip_set_iphash);
3581+}
3582+
f45e9687 3583+static void __exit ip_set_iphash_fini(void)
1aedc22c 3584+{
3585+ /* FIXME: possible race with ip_set_create() */
3586+ ip_set_unregister_set_type(&ip_set_iphash);
3587+}
3588+
f45e9687 3589+module_init(ip_set_iphash_init);
3590+module_exit(ip_set_iphash_fini);
7d2f026e 3591diff -uNrp --exclude=.svn a/net/ipv4/netfilter/ip_set_ipmap.c linux-2.6/net/ipv4/netfilter/ip_set_ipmap.c
3592--- a/net/ipv4/netfilter/ip_set_ipmap.c 1970-01-01 01:00:00.000000000 +0100
3593+++ linux-2.6/net/ipv4/netfilter/ip_set_ipmap.c 2008-07-08 16:52:53.965201208 +0200
3594@@ -0,0 +1,331 @@
1aedc22c 3595+/* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu>
3596+ * Patrick Schaaf <bof@bof.de>
3597+ * Copyright (C) 2003-2004 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
3598+ *
3599+ * This program is free software; you can redistribute it and/or modify
3600+ * it under the terms of the GNU General Public License version 2 as
7d2f026e 3601+ * published by the Free Software Foundation.
1aedc22c 3602+ */
3603+
3604+/* Kernel module implementing an IP set type: the single bitmap type */
3605+
3606+#include <linux/module.h>
3607+#include <linux/ip.h>
3608+#include <linux/skbuff.h>
f45e9687 3609+#include <linux/version.h>
1aedc22c 3610+#include <linux/netfilter_ipv4/ip_tables.h>
3611+#include <linux/netfilter_ipv4/ip_set.h>
3612+#include <linux/errno.h>
3613+#include <asm/uaccess.h>
3614+#include <asm/bitops.h>
3615+#include <linux/spinlock.h>
3616+
3617+#include <linux/netfilter_ipv4/ip_set_ipmap.h>
3618+
3619+static inline ip_set_ip_t
3620+ip_to_id(const struct ip_set_ipmap *map, ip_set_ip_t ip)
3621+{
3622+ return (ip - map->first_ip)/map->hosts;
3623+}
3624+
3625+static inline int
3626+__testip(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip)
3627+{
7d2f026e 3628+ struct ip_set_ipmap *map = set->data;
1aedc22c 3629+
3630+ if (ip < map->first_ip || ip > map->last_ip)
3631+ return -ERANGE;
3632+
3633+ *hash_ip = ip & map->netmask;
3634+ DP("set: %s, ip:%u.%u.%u.%u, %u.%u.%u.%u",
3635+ set->name, HIPQUAD(ip), HIPQUAD(*hash_ip));
3636+ return !!test_bit(ip_to_id(map, *hash_ip), map->members);
3637+}
3638+
3639+static int
3640+testip(struct ip_set *set, const void *data, size_t size,
3641+ ip_set_ip_t *hash_ip)
3642+{
7d2f026e 3643+ const struct ip_set_req_ipmap *req = data;
1aedc22c 3644+
3645+ if (size != sizeof(struct ip_set_req_ipmap)) {
3646+ ip_set_printk("data length wrong (want %zu, have %zu)",
3647+ sizeof(struct ip_set_req_ipmap),
3648+ size);
3649+ return -EINVAL;
3650+ }
3651+ return __testip(set, req->ip, hash_ip);
3652+}
3653+
3654+static int
7d2f026e 3655+testip_kernel(struct ip_set *set,
1aedc22c 3656+ const struct sk_buff *skb,
3657+ ip_set_ip_t *hash_ip,
3658+ const u_int32_t *flags,
3659+ unsigned char index)
3660+{
f45e9687 3661+ int res = __testip(set,
3662+ ntohl(flags[index] & IPSET_SRC
3663+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
7d2f026e 3664+ ? ip_hdr(skb)->saddr
5ce52adc 3665+ : ip_hdr(skb)->daddr),
f45e9687 3666+#else
7d2f026e 3667+ ? skb->nh.iph->saddr
f45e9687 3668+ : skb->nh.iph->daddr),
3669+#endif
1aedc22c 3670+ hash_ip);
3671+ return (res < 0 ? 0 : res);
3672+}
3673+
3674+static inline int
3675+__addip(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip)
3676+{
7d2f026e 3677+ struct ip_set_ipmap *map = set->data;
1aedc22c 3678+
3679+ if (ip < map->first_ip || ip > map->last_ip)
3680+ return -ERANGE;
3681+
3682+ *hash_ip = ip & map->netmask;
3683+ DP("%u.%u.%u.%u, %u.%u.%u.%u", HIPQUAD(ip), HIPQUAD(*hash_ip));
3684+ if (test_and_set_bit(ip_to_id(map, *hash_ip), map->members))
3685+ return -EEXIST;
3686+
3687+ return 0;
3688+}
3689+
3690+static int
3691+addip(struct ip_set *set, const void *data, size_t size,
3692+ ip_set_ip_t *hash_ip)
3693+{
7d2f026e 3694+ const struct ip_set_req_ipmap *req = data;
1aedc22c 3695+
3696+ if (size != sizeof(struct ip_set_req_ipmap)) {
3697+ ip_set_printk("data length wrong (want %zu, have %zu)",
3698+ sizeof(struct ip_set_req_ipmap),
3699+ size);
3700+ return -EINVAL;
3701+ }
3702+ DP("%u.%u.%u.%u", HIPQUAD(req->ip));
3703+ return __addip(set, req->ip, hash_ip);
3704+}
3705+
3706+static int
7d2f026e 3707+addip_kernel(struct ip_set *set,
1aedc22c 3708+ const struct sk_buff *skb,
3709+ ip_set_ip_t *hash_ip,
3710+ const u_int32_t *flags,
3711+ unsigned char index)
3712+{
3713+ return __addip(set,
7d2f026e 3714+ ntohl(flags[index] & IPSET_SRC
f45e9687 3715+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
7d2f026e 3716+ ? ip_hdr(skb)->saddr
5ce52adc 3717+ : ip_hdr(skb)->daddr),
f45e9687 3718+#else
7d2f026e 3719+ ? skb->nh.iph->saddr
f45e9687 3720+ : skb->nh.iph->daddr),
3721+#endif
1aedc22c 3722+ hash_ip);
3723+}
3724+
7d2f026e 3725+static inline int
1aedc22c 3726+__delip(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip)
3727+{
7d2f026e 3728+ struct ip_set_ipmap *map = set->data;
1aedc22c 3729+
3730+ if (ip < map->first_ip || ip > map->last_ip)
3731+ return -ERANGE;
3732+
3733+ *hash_ip = ip & map->netmask;
3734+ DP("%u.%u.%u.%u, %u.%u.%u.%u", HIPQUAD(ip), HIPQUAD(*hash_ip));
3735+ if (!test_and_clear_bit(ip_to_id(map, *hash_ip), map->members))
3736+ return -EEXIST;
3737+
3738+ return 0;
3739+}
3740+
3741+static int
3742+delip(struct ip_set *set, const void *data, size_t size,
3743+ ip_set_ip_t *hash_ip)
3744+{
7d2f026e 3745+ const struct ip_set_req_ipmap *req = data;
1aedc22c 3746+
3747+ if (size != sizeof(struct ip_set_req_ipmap)) {
3748+ ip_set_printk("data length wrong (want %zu, have %zu)",
3749+ sizeof(struct ip_set_req_ipmap),
3750+ size);
3751+ return -EINVAL;
3752+ }
3753+ return __delip(set, req->ip, hash_ip);
3754+}
3755+
3756+static int
3757+delip_kernel(struct ip_set *set,
3758+ const struct sk_buff *skb,
3759+ ip_set_ip_t *hash_ip,
3760+ const u_int32_t *flags,
3761+ unsigned char index)
3762+{
3763+ return __delip(set,
7d2f026e 3764+ ntohl(flags[index] & IPSET_SRC
f45e9687 3765+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
7d2f026e 3766+ ? ip_hdr(skb)->saddr
5ce52adc 3767+ : ip_hdr(skb)->daddr),
f45e9687 3768+#else
7d2f026e 3769+ ? skb->nh.iph->saddr
f45e9687 3770+ : skb->nh.iph->daddr),
3771+#endif
1aedc22c 3772+ hash_ip);
3773+}
3774+
3775+static int create(struct ip_set *set, const void *data, size_t size)
3776+{
3777+ int newbytes;
7d2f026e 3778+ const struct ip_set_req_ipmap_create *req = data;
1aedc22c 3779+ struct ip_set_ipmap *map;
3780+
3781+ if (size != sizeof(struct ip_set_req_ipmap_create)) {
3782+ ip_set_printk("data length wrong (want %zu, have %zu)",
3783+ sizeof(struct ip_set_req_ipmap_create),
3784+ size);
3785+ return -EINVAL;
3786+ }
3787+
3788+ DP("from %u.%u.%u.%u to %u.%u.%u.%u",
3789+ HIPQUAD(req->from), HIPQUAD(req->to));
3790+
3791+ if (req->from > req->to) {
3792+ DP("bad ip range");
3793+ return -ENOEXEC;
3794+ }
3795+
3796+ map = kmalloc(sizeof(struct ip_set_ipmap), GFP_KERNEL);
3797+ if (!map) {
3798+ DP("out of memory for %d bytes",
3799+ sizeof(struct ip_set_ipmap));
3800+ return -ENOMEM;
3801+ }
3802+ map->first_ip = req->from;
3803+ map->last_ip = req->to;
3804+ map->netmask = req->netmask;
3805+
3806+ if (req->netmask == 0xFFFFFFFF) {
3807+ map->hosts = 1;
3808+ map->sizeid = map->last_ip - map->first_ip + 1;
3809+ } else {
3810+ unsigned int mask_bits, netmask_bits;
3811+ ip_set_ip_t mask;
3812+
3813+ map->first_ip &= map->netmask; /* Should we better bark? */
3814+
3815+ mask = range_to_mask(map->first_ip, map->last_ip, &mask_bits);
3816+ netmask_bits = mask_to_bits(map->netmask);
3817+
3818+ if ((!mask && (map->first_ip || map->last_ip != 0xFFFFFFFF))
3819+ || netmask_bits <= mask_bits)
3820+ return -ENOEXEC;
3821+
3822+ DP("mask_bits %u, netmask_bits %u",
3823+ mask_bits, netmask_bits);
3824+ map->hosts = 2 << (32 - netmask_bits - 1);
3825+ map->sizeid = 2 << (netmask_bits - mask_bits - 1);
3826+ }
3827+ if (map->sizeid > MAX_RANGE + 1) {
3828+ ip_set_printk("range too big (max %d addresses)",
3829+ MAX_RANGE+1);
3830+ kfree(map);
3831+ return -ENOEXEC;
3832+ }
3833+ DP("hosts %u, sizeid %u", map->hosts, map->sizeid);
3834+ newbytes = bitmap_bytes(0, map->sizeid - 1);
3835+ map->members = kmalloc(newbytes, GFP_KERNEL);
3836+ if (!map->members) {
3837+ DP("out of memory for %d bytes", newbytes);
3838+ kfree(map);
3839+ return -ENOMEM;
3840+ }
3841+ memset(map->members, 0, newbytes);
3842+
3843+ set->data = map;
3844+ return 0;
3845+}
3846+
3847+static void destroy(struct ip_set *set)
3848+{
7d2f026e 3849+ struct ip_set_ipmap *map = set->data;
1aedc22c 3850+
3851+ kfree(map->members);
3852+ kfree(map);
3853+
3854+ set->data = NULL;
3855+}
3856+
3857+static void flush(struct ip_set *set)
3858+{
7d2f026e 3859+ struct ip_set_ipmap *map = set->data;
1aedc22c 3860+ memset(map->members, 0, bitmap_bytes(0, map->sizeid - 1));
3861+}
3862+
3863+static void list_header(const struct ip_set *set, void *data)
3864+{
7d2f026e 3865+ const struct ip_set_ipmap *map = set->data;
3866+ struct ip_set_req_ipmap_create *header = data;
1aedc22c 3867+
3868+ header->from = map->first_ip;
3869+ header->to = map->last_ip;
3870+ header->netmask = map->netmask;
3871+}
3872+
3873+static int list_members_size(const struct ip_set *set)
3874+{
7d2f026e 3875+ const struct ip_set_ipmap *map = set->data;
1aedc22c 3876+
3877+ return bitmap_bytes(0, map->sizeid - 1);
3878+}
3879+
3880+static void list_members(const struct ip_set *set, void *data)
3881+{
7d2f026e 3882+ const struct ip_set_ipmap *map = set->data;
1aedc22c 3883+ int bytes = bitmap_bytes(0, map->sizeid - 1);
3884+
3885+ memcpy(data, map->members, bytes);
3886+}
3887+
3888+static struct ip_set_type ip_set_ipmap = {
3889+ .typename = SETTYPE_NAME,
3890+ .features = IPSET_TYPE_IP | IPSET_DATA_SINGLE,
3891+ .protocol_version = IP_SET_PROTOCOL_VERSION,
3892+ .create = &create,
3893+ .destroy = &destroy,
3894+ .flush = &flush,
3895+ .reqsize = sizeof(struct ip_set_req_ipmap),
3896+ .addip = &addip,
3897+ .addip_kernel = &addip_kernel,
3898+ .delip = &delip,
3899+ .delip_kernel = &delip_kernel,
3900+ .testip = &testip,
3901+ .testip_kernel = &testip_kernel,
3902+ .header_size = sizeof(struct ip_set_req_ipmap_create),
3903+ .list_header = &list_header,
3904+ .list_members_size = &list_members_size,
3905+ .list_members = &list_members,
3906+ .me = THIS_MODULE,
3907+};
3908+
3909+MODULE_LICENSE("GPL");
3910+MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
3911+MODULE_DESCRIPTION("ipmap type of IP sets");
3912+
f45e9687 3913+static int __init ip_set_ipmap_init(void)
1aedc22c 3914+{
3915+ return ip_set_register_set_type(&ip_set_ipmap);
3916+}
3917+
f45e9687 3918+static void __exit ip_set_ipmap_fini(void)
1aedc22c 3919+{
3920+ /* FIXME: possible race with ip_set_create() */
3921+ ip_set_unregister_set_type(&ip_set_ipmap);
3922+}
3923+
f45e9687 3924+module_init(ip_set_ipmap_init);
3925+module_exit(ip_set_ipmap_fini);
7d2f026e 3926diff -uNrp --exclude=.svn a/net/ipv4/netfilter/ip_set_ipporthash.c linux-2.6/net/ipv4/netfilter/ip_set_ipporthash.c
3927--- a/net/ipv4/netfilter/ip_set_ipporthash.c 1970-01-01 01:00:00.000000000 +0100
3928+++ linux-2.6/net/ipv4/netfilter/ip_set_ipporthash.c 2008-07-08 16:52:53.965201208 +0200
3929@@ -0,0 +1,575 @@
1aedc22c 3930+/* Copyright (C) 2003-2004 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
3931+ *
3932+ * This program is free software; you can redistribute it and/or modify
3933+ * it under the terms of the GNU General Public License version 2 as
7d2f026e 3934+ * published by the Free Software Foundation.
1aedc22c 3935+ */
3936+
3937+/* Kernel module implementing an ip+port hash set */
3938+
3939+#include <linux/module.h>
3940+#include <linux/ip.h>
3941+#include <linux/tcp.h>
3942+#include <linux/udp.h>
3943+#include <linux/skbuff.h>
f45e9687 3944+#include <linux/version.h>
3945+#include <linux/jhash.h>
1aedc22c 3946+#include <linux/netfilter_ipv4/ip_tables.h>
3947+#include <linux/netfilter_ipv4/ip_set.h>
3948+#include <linux/errno.h>
3949+#include <asm/uaccess.h>
3950+#include <asm/bitops.h>
3951+#include <linux/spinlock.h>
3952+#include <linux/vmalloc.h>
3953+#include <linux/random.h>
3954+
3955+#include <net/ip.h>
3956+
3957+#include <linux/netfilter_ipv4/ip_set_malloc.h>
3958+#include <linux/netfilter_ipv4/ip_set_ipporthash.h>
1aedc22c 3959+
3960+static int limit = MAX_RANGE;
3961+
3962+/* We must handle non-linear skbs */
3963+static inline ip_set_ip_t
3964+get_port(const struct sk_buff *skb, u_int32_t flags)
3965+{
f45e9687 3966+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
5ce52adc 3967+ struct iphdr *iph = ip_hdr(skb);
f45e9687 3968+#else
3969+ struct iphdr *iph = skb->nh.iph;
3970+#endif
1aedc22c 3971+ u_int16_t offset = ntohs(iph->frag_off) & IP_OFFSET;
3972+
3973+ switch (iph->protocol) {
3974+ case IPPROTO_TCP: {
3975+ struct tcphdr tcph;
3976+
3977+ /* See comments at tcp_match in ip_tables.c */
3978+ if (offset)
3979+ return INVALID_PORT;
3980+
f45e9687 3981+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
5ce52adc 3982+ if (skb_copy_bits(skb, ip_hdr(skb)->ihl*4, &tcph, sizeof(tcph)) < 0)
f45e9687 3983+#else
3984+ if (skb_copy_bits(skb, skb->nh.iph->ihl*4, &tcph, sizeof(tcph)) < 0)
3985+#endif
1aedc22c 3986+ /* No choice either */
3987+ return INVALID_PORT;
3988+
3989+ return ntohs(flags & IPSET_SRC ?
3990+ tcph.source : tcph.dest);
3991+ }
3992+ case IPPROTO_UDP: {
3993+ struct udphdr udph;
3994+
3995+ if (offset)
3996+ return INVALID_PORT;
3997+
f45e9687 3998+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
5ce52adc 3999+ if (skb_copy_bits(skb, ip_hdr(skb)->ihl*4, &udph, sizeof(udph)) < 0)
f45e9687 4000+#else
4001+ if (skb_copy_bits(skb, skb->nh.iph->ihl*4, &udph, sizeof(udph)) < 0)
4002+#endif
1aedc22c 4003+ /* No choice either */
4004+ return INVALID_PORT;
4005+
4006+ return ntohs(flags & IPSET_SRC ?
4007+ udph.source : udph.dest);
4008+ }
4009+ default:
4010+ return INVALID_PORT;
4011+ }
4012+}
4013+
4014+static inline __u32
4015+jhash_ip(const struct ip_set_ipporthash *map, uint16_t i, ip_set_ip_t ip)
4016+{
4017+ return jhash_1word(ip, *(((uint32_t *) map->initval) + i));
4018+}
4019+
4020+#define HASH_IP(map, ip, port) (port + ((ip - ((map)->first_ip)) << 16))
4021+
4022+static inline __u32
4023+hash_id(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t port,
4024+ ip_set_ip_t *hash_ip)
4025+{
7d2f026e 4026+ struct ip_set_ipporthash *map = set->data;
1aedc22c 4027+ __u32 id;
4028+ u_int16_t i;
4029+ ip_set_ip_t *elem;
4030+
4031+ *hash_ip = HASH_IP(map, ip, port);
4032+ DP("set: %s, ipport:%u.%u.%u.%u:%u, %u.%u.%u.%u",
4033+ set->name, HIPQUAD(ip), port, HIPQUAD(*hash_ip));
4034+
4035+ for (i = 0; i < map->probes; i++) {
4036+ id = jhash_ip(map, i, *hash_ip) % map->hashsize;
4037+ DP("hash key: %u", id);
4038+ elem = HARRAY_ELEM(map->members, ip_set_ip_t *, id);
4039+ if (*elem == *hash_ip)
4040+ return id;
4041+ /* No shortcut at testing - there can be deleted
4042+ * entries. */
4043+ }
4044+ return UINT_MAX;
4045+}
4046+
4047+static inline int
4048+__testip(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t port,
4049+ ip_set_ip_t *hash_ip)
4050+{
7d2f026e 4051+ struct ip_set_ipporthash *map = set->data;
1aedc22c 4052+
4053+ if (ip < map->first_ip || ip > map->last_ip)
4054+ return -ERANGE;
4055+
4056+ return (hash_id(set, ip, port, hash_ip) != UINT_MAX);
4057+}
4058+
4059+static int
4060+testip(struct ip_set *set, const void *data, size_t size,
4061+ ip_set_ip_t *hash_ip)
4062+{
7d2f026e 4063+ const struct ip_set_req_ipporthash *req = data;
1aedc22c 4064+
4065+ if (size != sizeof(struct ip_set_req_ipporthash)) {
4066+ ip_set_printk("data length wrong (want %zu, have %zu)",
4067+ sizeof(struct ip_set_req_ipporthash),
4068+ size);
4069+ return -EINVAL;
4070+ }
4071+ return __testip(set, req->ip, req->port, hash_ip);
4072+}
4073+
4074+static int
7d2f026e 4075+testip_kernel(struct ip_set *set,
1aedc22c 4076+ const struct sk_buff *skb,
4077+ ip_set_ip_t *hash_ip,
4078+ const u_int32_t *flags,
4079+ unsigned char index)
4080+{
4081+ ip_set_ip_t port;
f45e9687 4082+ int res;
1aedc22c 4083+
4084+ if (flags[index+1] == 0)
f45e9687 4085+ return 0;
1aedc22c 4086+
4087+ port = get_port(skb, flags[index+1]);
4088+
4089+ DP("flag: %s src: %u.%u.%u.%u dst: %u.%u.%u.%u",
4090+ flags[index] & IPSET_SRC ? "SRC" : "DST",
f45e9687 4091+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
5ce52adc
JR
4092+ NIPQUAD(ip_hdr(skb)->saddr),
4093+ NIPQUAD(ip_hdr(skb)->daddr));
f45e9687 4094+#else
4095+ NIPQUAD(skb->nh.iph->saddr),
4096+ NIPQUAD(skb->nh.iph->daddr));
4097+#endif
1aedc22c 4098+ DP("flag %s port %u",
7d2f026e 4099+ flags[index+1] & IPSET_SRC ? "SRC" : "DST",
1aedc22c 4100+ port);
4101+ if (port == INVALID_PORT)
4102+ return 0;
4103+
f45e9687 4104+ res = __testip(set,
7d2f026e 4105+ ntohl(flags[index] & IPSET_SRC
f45e9687 4106+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
7d2f026e 4107+ ? ip_hdr(skb)->saddr
5ce52adc 4108+ : ip_hdr(skb)->daddr),
f45e9687 4109+#else
7d2f026e 4110+ ? skb->nh.iph->saddr
f45e9687 4111+ : skb->nh.iph->daddr),
4112+#endif
1aedc22c 4113+ port,
4114+ hash_ip);
f45e9687 4115+ return (res < 0 ? 0 : res);
4116+
1aedc22c 4117+}
4118+
4119+static inline int
4120+__add_haship(struct ip_set_ipporthash *map, ip_set_ip_t hash_ip)
4121+{
4122+ __u32 probe;
4123+ u_int16_t i;
4124+ ip_set_ip_t *elem;
4125+
4126+ for (i = 0; i < map->probes; i++) {
4127+ probe = jhash_ip(map, i, hash_ip) % map->hashsize;
4128+ elem = HARRAY_ELEM(map->members, ip_set_ip_t *, probe);
4129+ if (*elem == hash_ip)
4130+ return -EEXIST;
4131+ if (!*elem) {
4132+ *elem = hash_ip;
4133+ map->elements++;
4134+ return 0;
4135+ }
4136+ }
4137+ /* Trigger rehashing */
4138+ return -EAGAIN;
4139+}
4140+
4141+static inline int
4142+__addip(struct ip_set_ipporthash *map, ip_set_ip_t ip, ip_set_ip_t port,
4143+ ip_set_ip_t *hash_ip)
4144+{
4145+ if (map->elements > limit)
4146+ return -ERANGE;
4147+ if (ip < map->first_ip || ip > map->last_ip)
4148+ return -ERANGE;
4149+
4150+ *hash_ip = HASH_IP(map, ip, port);
4151+
4152+ return __add_haship(map, *hash_ip);
4153+}
4154+
4155+static int
4156+addip(struct ip_set *set, const void *data, size_t size,
4157+ ip_set_ip_t *hash_ip)
4158+{
7d2f026e 4159+ const struct ip_set_req_ipporthash *req = data;
1aedc22c 4160+
4161+ if (size != sizeof(struct ip_set_req_ipporthash)) {
4162+ ip_set_printk("data length wrong (want %zu, have %zu)",
4163+ sizeof(struct ip_set_req_ipporthash),
4164+ size);
4165+ return -EINVAL;
4166+ }
7d2f026e 4167+ return __addip(set->data, req->ip, req->port, hash_ip);
1aedc22c 4168+}
4169+
4170+static int
7d2f026e 4171+addip_kernel(struct ip_set *set,
1aedc22c 4172+ const struct sk_buff *skb,
4173+ ip_set_ip_t *hash_ip,
4174+ const u_int32_t *flags,
4175+ unsigned char index)
4176+{
4177+ ip_set_ip_t port;
4178+
4179+ if (flags[index+1] == 0)
4180+ return -EINVAL;
4181+
4182+ port = get_port(skb, flags[index+1]);
4183+
4184+ DP("flag: %s src: %u.%u.%u.%u dst: %u.%u.%u.%u",
4185+ flags[index] & IPSET_SRC ? "SRC" : "DST",
f45e9687 4186+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
5ce52adc
JR
4187+ NIPQUAD(ip_hdr(skb)->saddr),
4188+ NIPQUAD(ip_hdr(skb)->daddr));
f45e9687 4189+#else
4190+ NIPQUAD(skb->nh.iph->saddr),
4191+ NIPQUAD(skb->nh.iph->daddr));
4192+#endif
7d2f026e 4193+ DP("flag %s port %u",
4194+ flags[index+1] & IPSET_SRC ? "SRC" : "DST",
1aedc22c 4195+ port);
4196+ if (port == INVALID_PORT)
4197+ return -EINVAL;
4198+
7d2f026e 4199+ return __addip(set->data,
4200+ ntohl(flags[index] & IPSET_SRC
f45e9687 4201+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
7d2f026e 4202+ ? ip_hdr(skb)->saddr
5ce52adc 4203+ : ip_hdr(skb)->daddr),
f45e9687 4204+#else
7d2f026e 4205+ ? skb->nh.iph->saddr
f45e9687 4206+ : skb->nh.iph->daddr),
4207+#endif
1aedc22c 4208+ port,
4209+ hash_ip);
4210+}
4211+
4212+static int retry(struct ip_set *set)
4213+{
7d2f026e 4214+ struct ip_set_ipporthash *map = set->data;
1aedc22c 4215+ ip_set_ip_t *elem;
4216+ void *members;
4217+ u_int32_t i, hashsize = map->hashsize;
4218+ int res;
4219+ struct ip_set_ipporthash *tmp;
4220+
4221+ if (map->resize == 0)
4222+ return -ERANGE;
4223+
4224+ again:
4225+ res = 0;
4226+
4227+ /* Calculate new hash size */
4228+ hashsize += (hashsize * map->resize)/100;
4229+ if (hashsize == map->hashsize)
4230+ hashsize++;
4231+
4232+ ip_set_printk("rehashing of set %s triggered: "
4233+ "hashsize grows from %u to %u",
4234+ set->name, map->hashsize, hashsize);
4235+
7d2f026e 4236+ tmp = kmalloc(sizeof(struct ip_set_ipporthash)
1aedc22c 4237+ + map->probes * sizeof(uint32_t), GFP_ATOMIC);
4238+ if (!tmp) {
4239+ DP("out of memory for %d bytes",
4240+ sizeof(struct ip_set_ipporthash)
4241+ + map->probes * sizeof(uint32_t));
4242+ return -ENOMEM;
4243+ }
4244+ tmp->members = harray_malloc(hashsize, sizeof(ip_set_ip_t), GFP_ATOMIC);
4245+ if (!tmp->members) {
4246+ DP("out of memory for %d bytes", hashsize * sizeof(ip_set_ip_t));
4247+ kfree(tmp);
4248+ return -ENOMEM;
4249+ }
4250+ tmp->hashsize = hashsize;
4251+ tmp->elements = 0;
4252+ tmp->probes = map->probes;
4253+ tmp->resize = map->resize;
4254+ tmp->first_ip = map->first_ip;
4255+ tmp->last_ip = map->last_ip;
4256+ memcpy(tmp->initval, map->initval, map->probes * sizeof(uint32_t));
4257+
4258+ write_lock_bh(&set->lock);
7d2f026e 4259+ map = set->data; /* Play safe */
1aedc22c 4260+ for (i = 0; i < map->hashsize && res == 0; i++) {
4261+ elem = HARRAY_ELEM(map->members, ip_set_ip_t *, i);
4262+ if (*elem)
4263+ res = __add_haship(tmp, *elem);
4264+ }
4265+ if (res) {
4266+ /* Failure, try again */
4267+ write_unlock_bh(&set->lock);
4268+ harray_free(tmp->members);
4269+ kfree(tmp);
4270+ goto again;
4271+ }
4272+
4273+ /* Success at resizing! */
4274+ members = map->members;
4275+
4276+ map->hashsize = tmp->hashsize;
4277+ map->members = tmp->members;
4278+ write_unlock_bh(&set->lock);
4279+
4280+ harray_free(members);
4281+ kfree(tmp);
4282+
4283+ return 0;
4284+}
4285+
4286+static inline int
4287+__delip(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t port,
4288+ ip_set_ip_t *hash_ip)
4289+{
7d2f026e 4290+ struct ip_set_ipporthash *map = set->data;
1aedc22c 4291+ ip_set_ip_t id;
4292+ ip_set_ip_t *elem;
4293+
4294+ if (ip < map->first_ip || ip > map->last_ip)
4295+ return -ERANGE;
4296+
4297+ id = hash_id(set, ip, port, hash_ip);
4298+
4299+ if (id == UINT_MAX)
4300+ return -EEXIST;
4301+
4302+ elem = HARRAY_ELEM(map->members, ip_set_ip_t *, id);
4303+ *elem = 0;
4304+ map->elements--;
4305+
4306+ return 0;
4307+}
4308+
4309+static int
4310+delip(struct ip_set *set, const void *data, size_t size,
4311+ ip_set_ip_t *hash_ip)
4312+{
7d2f026e 4313+ const struct ip_set_req_ipporthash *req = data;
1aedc22c 4314+
4315+ if (size != sizeof(struct ip_set_req_ipporthash)) {
4316+ ip_set_printk("data length wrong (want %zu, have %zu)",
4317+ sizeof(struct ip_set_req_ipporthash),
4318+ size);
4319+ return -EINVAL;
4320+ }
4321+ return __delip(set, req->ip, req->port, hash_ip);
4322+}
4323+
4324+static int
7d2f026e 4325+delip_kernel(struct ip_set *set,
1aedc22c 4326+ const struct sk_buff *skb,
4327+ ip_set_ip_t *hash_ip,
4328+ const u_int32_t *flags,
4329+ unsigned char index)
4330+{
4331+ ip_set_ip_t port;
4332+
4333+ if (flags[index+1] == 0)
4334+ return -EINVAL;
4335+
4336+ port = get_port(skb, flags[index+1]);
4337+
4338+ DP("flag: %s src: %u.%u.%u.%u dst: %u.%u.%u.%u",
4339+ flags[index] & IPSET_SRC ? "SRC" : "DST",
f45e9687 4340+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
5ce52adc
JR
4341+ NIPQUAD(ip_hdr(skb)->saddr),
4342+ NIPQUAD(ip_hdr(skb)->daddr));
f45e9687 4343+#else
4344+ NIPQUAD(skb->nh.iph->saddr),
4345+ NIPQUAD(skb->nh.iph->daddr));
4346+#endif
1aedc22c 4347+ DP("flag %s port %u",
7d2f026e 4348+ flags[index+1] & IPSET_SRC ? "SRC" : "DST",
1aedc22c 4349+ port);
4350+ if (port == INVALID_PORT)
4351+ return -EINVAL;
4352+
4353+ return __delip(set,
7d2f026e 4354+ ntohl(flags[index] & IPSET_SRC
f45e9687 4355+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
7d2f026e 4356+ ? ip_hdr(skb)->saddr
5ce52adc 4357+ : ip_hdr(skb)->daddr),
f45e9687 4358+#else
7d2f026e 4359+ ? skb->nh.iph->saddr
f45e9687 4360+ : skb->nh.iph->daddr),
4361+#endif
1aedc22c 4362+ port,
4363+ hash_ip);
4364+}
4365+
4366+static int create(struct ip_set *set, const void *data, size_t size)
4367+{
7d2f026e 4368+ const struct ip_set_req_ipporthash_create *req = data;
1aedc22c 4369+ struct ip_set_ipporthash *map;
4370+ uint16_t i;
4371+
4372+ if (size != sizeof(struct ip_set_req_ipporthash_create)) {
4373+ ip_set_printk("data length wrong (want %zu, have %zu)",
4374+ sizeof(struct ip_set_req_ipporthash_create),
4375+ size);
4376+ return -EINVAL;
4377+ }
4378+
4379+ if (req->hashsize < 1) {
4380+ ip_set_printk("hashsize too small");
4381+ return -ENOEXEC;
4382+ }
4383+
4384+ if (req->probes < 1) {
4385+ ip_set_printk("probes too small");
4386+ return -ENOEXEC;
4387+ }
4388+
7d2f026e 4389+ map = kmalloc(sizeof(struct ip_set_ipporthash)
1aedc22c 4390+ + req->probes * sizeof(uint32_t), GFP_KERNEL);
4391+ if (!map) {
4392+ DP("out of memory for %d bytes",
4393+ sizeof(struct ip_set_ipporthash)
4394+ + req->probes * sizeof(uint32_t));
4395+ return -ENOMEM;
4396+ }
4397+ for (i = 0; i < req->probes; i++)
4398+ get_random_bytes(((uint32_t *) map->initval)+i, 4);
4399+ map->elements = 0;
4400+ map->hashsize = req->hashsize;
4401+ map->probes = req->probes;
4402+ map->resize = req->resize;
4403+ map->first_ip = req->from;
4404+ map->last_ip = req->to;
4405+ map->members = harray_malloc(map->hashsize, sizeof(ip_set_ip_t), GFP_KERNEL);
4406+ if (!map->members) {
4407+ DP("out of memory for %d bytes", map->hashsize * sizeof(ip_set_ip_t));
4408+ kfree(map);
4409+ return -ENOMEM;
4410+ }
4411+
4412+ set->data = map;
4413+ return 0;
4414+}
4415+
4416+static void destroy(struct ip_set *set)
4417+{
7d2f026e 4418+ struct ip_set_ipporthash *map = set->data;
1aedc22c 4419+
4420+ harray_free(map->members);
4421+ kfree(map);
4422+
4423+ set->data = NULL;
4424+}
4425+
4426+static void flush(struct ip_set *set)
4427+{
7d2f026e 4428+ struct ip_set_ipporthash *map = set->data;
1aedc22c 4429+ harray_flush(map->members, map->hashsize, sizeof(ip_set_ip_t));
4430+ map->elements = 0;
4431+}
4432+
4433+static void list_header(const struct ip_set *set, void *data)
4434+{
7d2f026e 4435+ const struct ip_set_ipporthash *map = set->data;
4436+ struct ip_set_req_ipporthash_create *header = data;
1aedc22c 4437+
4438+ header->hashsize = map->hashsize;
4439+ header->probes = map->probes;
4440+ header->resize = map->resize;
4441+ header->from = map->first_ip;
4442+ header->to = map->last_ip;
4443+}
4444+
4445+static int list_members_size(const struct ip_set *set)
4446+{
7d2f026e 4447+ const struct ip_set_ipporthash *map = set->data;
1aedc22c 4448+
4449+ return (map->hashsize * sizeof(ip_set_ip_t));
4450+}
4451+
4452+static void list_members(const struct ip_set *set, void *data)
4453+{
7d2f026e 4454+ const struct ip_set_ipporthash *map = set->data;
1aedc22c 4455+ ip_set_ip_t i, *elem;
4456+
4457+ for (i = 0; i < map->hashsize; i++) {
4458+ elem = HARRAY_ELEM(map->members, ip_set_ip_t *, i);
4459+ ((ip_set_ip_t *)data)[i] = *elem;
4460+ }
4461+}
4462+
4463+static struct ip_set_type ip_set_ipporthash = {
4464+ .typename = SETTYPE_NAME,
4465+ .features = IPSET_TYPE_IP | IPSET_TYPE_PORT | IPSET_DATA_DOUBLE,
4466+ .protocol_version = IP_SET_PROTOCOL_VERSION,
4467+ .create = &create,
4468+ .destroy = &destroy,
4469+ .flush = &flush,
4470+ .reqsize = sizeof(struct ip_set_req_ipporthash),
4471+ .addip = &addip,
4472+ .addip_kernel = &addip_kernel,
4473+ .retry = &retry,
4474+ .delip = &delip,
4475+ .delip_kernel = &delip_kernel,
4476+ .testip = &testip,
4477+ .testip_kernel = &testip_kernel,
4478+ .header_size = sizeof(struct ip_set_req_ipporthash_create),
4479+ .list_header = &list_header,
4480+ .list_members_size = &list_members_size,
4481+ .list_members = &list_members,
4482+ .me = THIS_MODULE,
4483+};
4484+
4485+MODULE_LICENSE("GPL");
4486+MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
4487+MODULE_DESCRIPTION("ipporthash type of IP sets");
4488+module_param(limit, int, 0600);
4489+MODULE_PARM_DESC(limit, "maximal number of elements stored in the sets");
4490+
f45e9687 4491+static int __init ip_set_ipporthash_init(void)
1aedc22c 4492+{
7d2f026e 4493+ init_max_page_size();
1aedc22c 4494+ return ip_set_register_set_type(&ip_set_ipporthash);
4495+}
4496+
f45e9687 4497+static void __exit ip_set_ipporthash_fini(void)
1aedc22c 4498+{
4499+ /* FIXME: possible race with ip_set_create() */
4500+ ip_set_unregister_set_type(&ip_set_ipporthash);
4501+}
4502+
f45e9687 4503+module_init(ip_set_ipporthash_init);
4504+module_exit(ip_set_ipporthash_fini);
7d2f026e 4505diff -uNrp --exclude=.svn a/net/ipv4/netfilter/ip_set_iptree.c linux-2.6/net/ipv4/netfilter/ip_set_iptree.c
4506--- a/net/ipv4/netfilter/ip_set_iptree.c 1970-01-01 01:00:00.000000000 +0100
4507+++ linux-2.6/net/ipv4/netfilter/ip_set_iptree.c 2008-07-08 16:52:53.965201208 +0200
4508@@ -0,0 +1,607 @@
1aedc22c 4509+/* Copyright (C) 2005 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
4510+ *
4511+ * This program is free software; you can redistribute it and/or modify
4512+ * it under the terms of the GNU General Public License version 2 as
7d2f026e 4513+ * published by the Free Software Foundation.
1aedc22c 4514+ */
4515+
4516+/* Kernel module implementing an IP set type: the iptree type */
4517+
9f54053a 4518+#include <linux/version.h>
1aedc22c 4519+#include <linux/module.h>
4520+#include <linux/ip.h>
4521+#include <linux/skbuff.h>
4522+#include <linux/slab.h>
4523+#include <linux/delay.h>
4524+#include <linux/netfilter_ipv4/ip_tables.h>
4525+#include <linux/netfilter_ipv4/ip_set.h>
4526+#include <linux/errno.h>
4527+#include <asm/uaccess.h>
4528+#include <asm/bitops.h>
4529+#include <linux/spinlock.h>
4530+
4531+/* Backward compatibility */
4532+#ifndef __nocast
4533+#define __nocast
4534+#endif
4535+
4536+#include <linux/netfilter_ipv4/ip_set_iptree.h>
4537+
4538+static int limit = MAX_RANGE;
4539+
4540+/* Garbage collection interval in seconds: */
4541+#define IPTREE_GC_TIME 5*60
7d2f026e 4542+/* Sleep so many milliseconds before trying again
4543+ * to delete the gc timer at destroying/flushing a set */
1aedc22c 4544+#define IPTREE_DESTROY_SLEEP 100
4545+
9f54053a 4546+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21)
ca74d27b 4547+static struct kmem_cache *branch_cachep;
4548+static struct kmem_cache *leaf_cachep;
9f54053a
JR
4549+#else
4550+static kmem_cache_t *branch_cachep;
4551+static kmem_cache_t *leaf_cachep;
4552+#endif
1aedc22c 4553+
f45e9687 4554+#if defined(__LITTLE_ENDIAN)
1aedc22c 4555+#define ABCD(a,b,c,d,addrp) do { \
4556+ a = ((unsigned char *)addrp)[3]; \
4557+ b = ((unsigned char *)addrp)[2]; \
4558+ c = ((unsigned char *)addrp)[1]; \
4559+ d = ((unsigned char *)addrp)[0]; \
4560+} while (0)
f45e9687 4561+#elif defined(__BIG_ENDIAN)
4562+#define ABCD(a,b,c,d,addrp) do { \
4563+ a = ((unsigned char *)addrp)[0]; \
4564+ b = ((unsigned char *)addrp)[1]; \
4565+ c = ((unsigned char *)addrp)[2]; \
4566+ d = ((unsigned char *)addrp)[3]; \
4567+} while (0)
4568+#else
4569+#error "Please fix asm/byteorder.h"
4570+#endif /* __LITTLE_ENDIAN */
1aedc22c 4571+
4572+#define TESTIP_WALK(map, elem, branch) do { \
4573+ if ((map)->tree[elem]) { \
4574+ branch = (map)->tree[elem]; \
4575+ } else \
4576+ return 0; \
4577+} while (0)
4578+
4579+static inline int
4580+__testip(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip)
4581+{
7d2f026e 4582+ struct ip_set_iptree *map = set->data;
1aedc22c 4583+ struct ip_set_iptreeb *btree;
4584+ struct ip_set_iptreec *ctree;
4585+ struct ip_set_iptreed *dtree;
4586+ unsigned char a,b,c,d;
4587+
4588+ if (!ip)
4589+ return -ERANGE;
4590+
4591+ *hash_ip = ip;
4592+ ABCD(a, b, c, d, hash_ip);
4593+ DP("%u %u %u %u timeout %u", a, b, c, d, map->timeout);
4594+ TESTIP_WALK(map, a, btree);
4595+ TESTIP_WALK(btree, b, ctree);
4596+ TESTIP_WALK(ctree, c, dtree);
4597+ DP("%lu %lu", dtree->expires[d], jiffies);
f45e9687 4598+ return dtree->expires[d]
4599+ && (!map->timeout
4600+ || time_after(dtree->expires[d], jiffies));
1aedc22c 4601+}
4602+
4603+static int
4604+testip(struct ip_set *set, const void *data, size_t size,
4605+ ip_set_ip_t *hash_ip)
4606+{
7d2f026e 4607+ const struct ip_set_req_iptree *req = data;
1aedc22c 4608+
4609+ if (size != sizeof(struct ip_set_req_iptree)) {
4610+ ip_set_printk("data length wrong (want %zu, have %zu)",
4611+ sizeof(struct ip_set_req_iptree),
4612+ size);
4613+ return -EINVAL;
4614+ }
4615+ return __testip(set, req->ip, hash_ip);
4616+}
4617+
4618+static int
7d2f026e 4619+testip_kernel(struct ip_set *set,
1aedc22c 4620+ const struct sk_buff *skb,
4621+ ip_set_ip_t *hash_ip,
4622+ const u_int32_t *flags,
4623+ unsigned char index)
4624+{
4625+ int res;
4626+
4627+ DP("flag: %s src: %u.%u.%u.%u dst: %u.%u.%u.%u",
4628+ flags[index] & IPSET_SRC ? "SRC" : "DST",
f45e9687 4629+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
5ce52adc
JR
4630+ NIPQUAD(ip_hdr(skb)->saddr),
4631+ NIPQUAD(ip_hdr(skb)->daddr));
f45e9687 4632+#else
4633+ NIPQUAD(skb->nh.iph->saddr),
4634+ NIPQUAD(skb->nh.iph->daddr));
4635+#endif
1aedc22c 4636+
4637+ res = __testip(set,
7d2f026e 4638+ ntohl(flags[index] & IPSET_SRC
f45e9687 4639+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
7d2f026e 4640+ ? ip_hdr(skb)->saddr
5ce52adc 4641+ : ip_hdr(skb)->daddr),
f45e9687 4642+#else
7d2f026e 4643+ ? skb->nh.iph->saddr
f45e9687 4644+ : skb->nh.iph->daddr),
4645+#endif
1aedc22c 4646+ hash_ip);
4647+ return (res < 0 ? 0 : res);
4648+}
4649+
f45e9687 4650+#define ADDIP_WALK(map, elem, branch, type, cachep) do { \
1aedc22c 4651+ if ((map)->tree[elem]) { \
4652+ DP("found %u", elem); \
4653+ branch = (map)->tree[elem]; \
4654+ } else { \
4655+ branch = (type *) \
f45e9687 4656+ kmem_cache_alloc(cachep, GFP_ATOMIC); \
1aedc22c 4657+ if (branch == NULL) \
4658+ return -ENOMEM; \
4659+ memset(branch, 0, sizeof(*branch)); \
4660+ (map)->tree[elem] = branch; \
4661+ DP("alloc %u", elem); \
4662+ } \
4663+} while (0)
4664+
4665+static inline int
4666+__addip(struct ip_set *set, ip_set_ip_t ip, unsigned int timeout,
f45e9687 4667+ ip_set_ip_t *hash_ip)
1aedc22c 4668+{
7d2f026e 4669+ struct ip_set_iptree *map = set->data;
1aedc22c 4670+ struct ip_set_iptreeb *btree;
4671+ struct ip_set_iptreec *ctree;
4672+ struct ip_set_iptreed *dtree;
4673+ unsigned char a,b,c,d;
4674+ int ret = 0;
4675+
f45e9687 4676+ if (!ip || map->elements >= limit)
1aedc22c 4677+ /* We could call the garbage collector
4678+ * but it's probably overkill */
4679+ return -ERANGE;
4680+
4681+ *hash_ip = ip;
4682+ ABCD(a, b, c, d, hash_ip);
4683+ DP("%u %u %u %u timeout %u", a, b, c, d, timeout);
f45e9687 4684+ ADDIP_WALK(map, a, btree, struct ip_set_iptreeb, branch_cachep);
4685+ ADDIP_WALK(btree, b, ctree, struct ip_set_iptreec, branch_cachep);
4686+ ADDIP_WALK(ctree, c, dtree, struct ip_set_iptreed, leaf_cachep);
1aedc22c 4687+ if (dtree->expires[d]
4688+ && (!map->timeout || time_after(dtree->expires[d], jiffies)))
4689+ ret = -EEXIST;
4690+ dtree->expires[d] = map->timeout ? (timeout * HZ + jiffies) : 1;
f45e9687 4691+ /* Lottery: I won! */
1aedc22c 4692+ if (dtree->expires[d] == 0)
4693+ dtree->expires[d] = 1;
4694+ DP("%u %lu", d, dtree->expires[d]);
4695+ if (ret == 0)
4696+ map->elements++;
4697+ return ret;
4698+}
4699+
4700+static int
4701+addip(struct ip_set *set, const void *data, size_t size,
4702+ ip_set_ip_t *hash_ip)
4703+{
7d2f026e 4704+ struct ip_set_iptree *map = set->data;
4705+ const struct ip_set_req_iptree *req = data;
1aedc22c 4706+
4707+ if (size != sizeof(struct ip_set_req_iptree)) {
4708+ ip_set_printk("data length wrong (want %zu, have %zu)",
4709+ sizeof(struct ip_set_req_iptree),
4710+ size);
4711+ return -EINVAL;
4712+ }
4713+ DP("%u.%u.%u.%u %u", HIPQUAD(req->ip), req->timeout);
4714+ return __addip(set, req->ip,
4715+ req->timeout ? req->timeout : map->timeout,
f45e9687 4716+ hash_ip);
1aedc22c 4717+}
4718+
4719+static int
7d2f026e 4720+addip_kernel(struct ip_set *set,
1aedc22c 4721+ const struct sk_buff *skb,
4722+ ip_set_ip_t *hash_ip,
4723+ const u_int32_t *flags,
4724+ unsigned char index)
4725+{
7d2f026e 4726+ struct ip_set_iptree *map = set->data;
1aedc22c 4727+
4728+ return __addip(set,
7d2f026e 4729+ ntohl(flags[index] & IPSET_SRC
f45e9687 4730+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
7d2f026e 4731+ ? ip_hdr(skb)->saddr
5ce52adc 4732+ : ip_hdr(skb)->daddr),
f45e9687 4733+#else
7d2f026e 4734+ ? skb->nh.iph->saddr
f45e9687 4735+ : skb->nh.iph->daddr),
4736+#endif
1aedc22c 4737+ map->timeout,
f45e9687 4738+ hash_ip);
1aedc22c 4739+}
4740+
4741+#define DELIP_WALK(map, elem, branch) do { \
4742+ if ((map)->tree[elem]) { \
4743+ branch = (map)->tree[elem]; \
4744+ } else \
4745+ return -EEXIST; \
4746+} while (0)
4747+
7d2f026e 4748+static inline int
1aedc22c 4749+__delip(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip)
4750+{
7d2f026e 4751+ struct ip_set_iptree *map = set->data;
1aedc22c 4752+ struct ip_set_iptreeb *btree;
4753+ struct ip_set_iptreec *ctree;
4754+ struct ip_set_iptreed *dtree;
4755+ unsigned char a,b,c,d;
4756+
4757+ if (!ip)
4758+ return -ERANGE;
4759+
4760+ *hash_ip = ip;
4761+ ABCD(a, b, c, d, hash_ip);
4762+ DELIP_WALK(map, a, btree);
4763+ DELIP_WALK(btree, b, ctree);
4764+ DELIP_WALK(ctree, c, dtree);
4765+
4766+ if (dtree->expires[d]) {
4767+ dtree->expires[d] = 0;
4768+ map->elements--;
4769+ return 0;
4770+ }
4771+ return -EEXIST;
4772+}
4773+
4774+static int
4775+delip(struct ip_set *set, const void *data, size_t size,
4776+ ip_set_ip_t *hash_ip)
4777+{
7d2f026e 4778+ const struct ip_set_req_iptree *req = data;
1aedc22c 4779+
4780+ if (size != sizeof(struct ip_set_req_iptree)) {
4781+ ip_set_printk("data length wrong (want %zu, have %zu)",
4782+ sizeof(struct ip_set_req_iptree),
4783+ size);
4784+ return -EINVAL;
4785+ }
4786+ return __delip(set, req->ip, hash_ip);
4787+}
4788+
4789+static int
7d2f026e 4790+delip_kernel(struct ip_set *set,
1aedc22c 4791+ const struct sk_buff *skb,
4792+ ip_set_ip_t *hash_ip,
4793+ const u_int32_t *flags,
4794+ unsigned char index)
4795+{
4796+ return __delip(set,
7d2f026e 4797+ ntohl(flags[index] & IPSET_SRC
f45e9687 4798+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
7d2f026e 4799+ ? ip_hdr(skb)->saddr
5ce52adc 4800+ : ip_hdr(skb)->daddr),
f45e9687 4801+#else
7d2f026e 4802+ ? skb->nh.iph->saddr
f45e9687 4803+ : skb->nh.iph->daddr),
4804+#endif
1aedc22c 4805+ hash_ip);
4806+}
4807+
4808+#define LOOP_WALK_BEGIN(map, i, branch) \
4809+ for (i = 0; i < 256; i++) { \
4810+ if (!(map)->tree[i]) \
4811+ continue; \
4812+ branch = (map)->tree[i]
4813+
4814+#define LOOP_WALK_END }
4815+
4816+static void ip_tree_gc(unsigned long ul_set)
4817+{
7d2f026e 4818+ struct ip_set *set = (struct ip_set *) ul_set;
4819+ struct ip_set_iptree *map = set->data;
1aedc22c 4820+ struct ip_set_iptreeb *btree;
4821+ struct ip_set_iptreec *ctree;
4822+ struct ip_set_iptreed *dtree;
4823+ unsigned int a,b,c,d;
4824+ unsigned char i,j,k;
4825+
4826+ i = j = k = 0;
4827+ DP("gc: %s", set->name);
4828+ write_lock_bh(&set->lock);
4829+ LOOP_WALK_BEGIN(map, a, btree);
4830+ LOOP_WALK_BEGIN(btree, b, ctree);
4831+ LOOP_WALK_BEGIN(ctree, c, dtree);
4832+ for (d = 0; d < 256; d++) {
4833+ if (dtree->expires[d]) {
4834+ DP("gc: %u %u %u %u: expires %lu jiffies %lu",
4835+ a, b, c, d,
4836+ dtree->expires[d], jiffies);
4837+ if (map->timeout
4838+ && time_before(dtree->expires[d], jiffies)) {
4839+ dtree->expires[d] = 0;
4840+ map->elements--;
4841+ } else
4842+ k = 1;
4843+ }
4844+ }
4845+ if (k == 0) {
4846+ DP("gc: %s: leaf %u %u %u empty",
4847+ set->name, a, b, c);
4848+ kmem_cache_free(leaf_cachep, dtree);
4849+ ctree->tree[c] = NULL;
4850+ } else {
4851+ DP("gc: %s: leaf %u %u %u not empty",
4852+ set->name, a, b, c);
4853+ j = 1;
4854+ k = 0;
4855+ }
4856+ LOOP_WALK_END;
4857+ if (j == 0) {
4858+ DP("gc: %s: branch %u %u empty",
4859+ set->name, a, b);
4860+ kmem_cache_free(branch_cachep, ctree);
4861+ btree->tree[b] = NULL;
4862+ } else {
4863+ DP("gc: %s: branch %u %u not empty",
4864+ set->name, a, b);
4865+ i = 1;
4866+ j = k = 0;
4867+ }
4868+ LOOP_WALK_END;
4869+ if (i == 0) {
4870+ DP("gc: %s: branch %u empty",
4871+ set->name, a);
4872+ kmem_cache_free(branch_cachep, btree);
4873+ map->tree[a] = NULL;
4874+ } else {
4875+ DP("gc: %s: branch %u not empty",
4876+ set->name, a);
4877+ i = j = k = 0;
4878+ }
4879+ LOOP_WALK_END;
4880+ write_unlock_bh(&set->lock);
4881+
4882+ map->gc.expires = jiffies + map->gc_interval * HZ;
4883+ add_timer(&map->gc);
4884+}
4885+
4886+static inline void init_gc_timer(struct ip_set *set)
4887+{
7d2f026e 4888+ struct ip_set_iptree *map = set->data;
1aedc22c 4889+
4890+ /* Even if there is no timeout for the entries,
4891+ * we still have to call gc because delete
4892+ * do not clean up empty branches */
4893+ map->gc_interval = IPTREE_GC_TIME;
4894+ init_timer(&map->gc);
4895+ map->gc.data = (unsigned long) set;
4896+ map->gc.function = ip_tree_gc;
4897+ map->gc.expires = jiffies + map->gc_interval * HZ;
4898+ add_timer(&map->gc);
4899+}
4900+
4901+static int create(struct ip_set *set, const void *data, size_t size)
4902+{
7d2f026e 4903+ const struct ip_set_req_iptree_create *req = data;
1aedc22c 4904+ struct ip_set_iptree *map;
4905+
4906+ if (size != sizeof(struct ip_set_req_iptree_create)) {
4907+ ip_set_printk("data length wrong (want %zu, have %zu)",
4908+ sizeof(struct ip_set_req_iptree_create),
4909+ size);
4910+ return -EINVAL;
4911+ }
4912+
4913+ map = kmalloc(sizeof(struct ip_set_iptree), GFP_KERNEL);
4914+ if (!map) {
4915+ DP("out of memory for %d bytes",
4916+ sizeof(struct ip_set_iptree));
4917+ return -ENOMEM;
4918+ }
4919+ memset(map, 0, sizeof(*map));
4920+ map->timeout = req->timeout;
4921+ map->elements = 0;
4922+ set->data = map;
4923+
4924+ init_gc_timer(set);
4925+
4926+ return 0;
4927+}
4928+
4929+static void __flush(struct ip_set_iptree *map)
4930+{
4931+ struct ip_set_iptreeb *btree;
4932+ struct ip_set_iptreec *ctree;
4933+ struct ip_set_iptreed *dtree;
4934+ unsigned int a,b,c;
4935+
4936+ LOOP_WALK_BEGIN(map, a, btree);
4937+ LOOP_WALK_BEGIN(btree, b, ctree);
4938+ LOOP_WALK_BEGIN(ctree, c, dtree);
4939+ kmem_cache_free(leaf_cachep, dtree);
4940+ LOOP_WALK_END;
4941+ kmem_cache_free(branch_cachep, ctree);
4942+ LOOP_WALK_END;
4943+ kmem_cache_free(branch_cachep, btree);
4944+ LOOP_WALK_END;
4945+ map->elements = 0;
4946+}
4947+
4948+static void destroy(struct ip_set *set)
4949+{
7d2f026e 4950+ struct ip_set_iptree *map = set->data;
1aedc22c 4951+
4952+ /* gc might be running */
4953+ while (!del_timer(&map->gc))
4954+ msleep(IPTREE_DESTROY_SLEEP);
4955+ __flush(map);
4956+ kfree(map);
4957+ set->data = NULL;
4958+}
4959+
4960+static void flush(struct ip_set *set)
4961+{
7d2f026e 4962+ struct ip_set_iptree *map = set->data;
1aedc22c 4963+ unsigned int timeout = map->timeout;
4964+
4965+ /* gc might be running */
4966+ while (!del_timer(&map->gc))
4967+ msleep(IPTREE_DESTROY_SLEEP);
4968+ __flush(map);
4969+ memset(map, 0, sizeof(*map));
4970+ map->timeout = timeout;
4971+
4972+ init_gc_timer(set);
4973+}
4974+
4975+static void list_header(const struct ip_set *set, void *data)
4976+{
7d2f026e 4977+ const struct ip_set_iptree *map = set->data;
4978+ struct ip_set_req_iptree_create *header = data;
1aedc22c 4979+
4980+ header->timeout = map->timeout;
4981+}
4982+
4983+static int list_members_size(const struct ip_set *set)
4984+{
7d2f026e 4985+ const struct ip_set_iptree *map = set->data;
1aedc22c 4986+ struct ip_set_iptreeb *btree;
4987+ struct ip_set_iptreec *ctree;
4988+ struct ip_set_iptreed *dtree;
4989+ unsigned int a,b,c,d;
4990+ unsigned int count = 0;
4991+
4992+ LOOP_WALK_BEGIN(map, a, btree);
4993+ LOOP_WALK_BEGIN(btree, b, ctree);
4994+ LOOP_WALK_BEGIN(ctree, c, dtree);
4995+ for (d = 0; d < 256; d++) {
4996+ if (dtree->expires[d]
4997+ && (!map->timeout || time_after(dtree->expires[d], jiffies)))
4998+ count++;
4999+ }
5000+ LOOP_WALK_END;
5001+ LOOP_WALK_END;
5002+ LOOP_WALK_END;
5003+
5004+ DP("members %u", count);
5005+ return (count * sizeof(struct ip_set_req_iptree));
5006+}
5007+
5008+static void list_members(const struct ip_set *set, void *data)
5009+{
7d2f026e 5010+ const struct ip_set_iptree *map = set->data;
1aedc22c 5011+ struct ip_set_iptreeb *btree;
5012+ struct ip_set_iptreec *ctree;
5013+ struct ip_set_iptreed *dtree;
5014+ unsigned int a,b,c,d;
5015+ size_t offset = 0;
5016+ struct ip_set_req_iptree *entry;
5017+
5018+ LOOP_WALK_BEGIN(map, a, btree);
5019+ LOOP_WALK_BEGIN(btree, b, ctree);
5020+ LOOP_WALK_BEGIN(ctree, c, dtree);
5021+ for (d = 0; d < 256; d++) {
5022+ if (dtree->expires[d]
5023+ && (!map->timeout || time_after(dtree->expires[d], jiffies))) {
7d2f026e 5024+ entry = data + offset;
1aedc22c 5025+ entry->ip = ((a << 24) | (b << 16) | (c << 8) | d);
7d2f026e 5026+ entry->timeout = !map->timeout ? 0
1aedc22c 5027+ : (dtree->expires[d] - jiffies)/HZ;
5028+ offset += sizeof(struct ip_set_req_iptree);
5029+ }
5030+ }
5031+ LOOP_WALK_END;
5032+ LOOP_WALK_END;
5033+ LOOP_WALK_END;
5034+}
5035+
5036+static struct ip_set_type ip_set_iptree = {
5037+ .typename = SETTYPE_NAME,
5038+ .features = IPSET_TYPE_IP | IPSET_DATA_SINGLE,
5039+ .protocol_version = IP_SET_PROTOCOL_VERSION,
5040+ .create = &create,
5041+ .destroy = &destroy,
5042+ .flush = &flush,
5043+ .reqsize = sizeof(struct ip_set_req_iptree),
5044+ .addip = &addip,
5045+ .addip_kernel = &addip_kernel,
5046+ .delip = &delip,
5047+ .delip_kernel = &delip_kernel,
5048+ .testip = &testip,
5049+ .testip_kernel = &testip_kernel,
5050+ .header_size = sizeof(struct ip_set_req_iptree_create),
5051+ .list_header = &list_header,
5052+ .list_members_size = &list_members_size,
5053+ .list_members = &list_members,
5054+ .me = THIS_MODULE,
5055+};
5056+
5057+MODULE_LICENSE("GPL");
5058+MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
5059+MODULE_DESCRIPTION("iptree type of IP sets");
5060+module_param(limit, int, 0600);
5061+MODULE_PARM_DESC(limit, "maximal number of elements stored in the sets");
5062+
f45e9687 5063+static int __init ip_set_iptree_init(void)
1aedc22c 5064+{
5065+ int ret;
5066+
f45e9687 5067+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,23)
5068+ branch_cachep = kmem_cache_create("ip_set_iptreeb",
5069+ sizeof(struct ip_set_iptreeb),
5070+ 0, 0, NULL);
5071+#else
1aedc22c 5072+ branch_cachep = kmem_cache_create("ip_set_iptreeb",
5073+ sizeof(struct ip_set_iptreeb),
5074+ 0, 0, NULL, NULL);
f45e9687 5075+#endif
1aedc22c 5076+ if (!branch_cachep) {
5077+ printk(KERN_ERR "Unable to create ip_set_iptreeb slab cache\n");
5078+ ret = -ENOMEM;
5079+ goto out;
5080+ }
f45e9687 5081+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,23)
5082+ leaf_cachep = kmem_cache_create("ip_set_iptreed",
5083+ sizeof(struct ip_set_iptreed),
5084+ 0, 0, NULL);
5085+#else
1aedc22c 5086+ leaf_cachep = kmem_cache_create("ip_set_iptreed",
5087+ sizeof(struct ip_set_iptreed),
5088+ 0, 0, NULL, NULL);
f45e9687 5089+#endif
1aedc22c 5090+ if (!leaf_cachep) {
5091+ printk(KERN_ERR "Unable to create ip_set_iptreed slab cache\n");
5092+ ret = -ENOMEM;
5093+ goto free_branch;
5094+ }
5095+ ret = ip_set_register_set_type(&ip_set_iptree);
5096+ if (ret == 0)
5097+ goto out;
5098+
5099+ kmem_cache_destroy(leaf_cachep);
5100+ free_branch:
5101+ kmem_cache_destroy(branch_cachep);
5102+ out:
5103+ return ret;
5104+}
5105+
f45e9687 5106+static void __exit ip_set_iptree_fini(void)
1aedc22c 5107+{
5108+ /* FIXME: possible race with ip_set_create() */
5109+ ip_set_unregister_set_type(&ip_set_iptree);
5110+ kmem_cache_destroy(leaf_cachep);
5111+ kmem_cache_destroy(branch_cachep);
5112+}
5113+
f45e9687 5114+module_init(ip_set_iptree_init);
5115+module_exit(ip_set_iptree_fini);
7d2f026e 5116diff -uNrp --exclude=.svn a/net/ipv4/netfilter/ip_set_iptreemap.c linux-2.6/net/ipv4/netfilter/ip_set_iptreemap.c
5117--- a/net/ipv4/netfilter/ip_set_iptreemap.c 1970-01-01 01:00:00.000000000 +0100
5118+++ linux-2.6/net/ipv4/netfilter/ip_set_iptreemap.c 2008-07-08 16:52:53.965201208 +0200
5119@@ -0,0 +1,827 @@
f45e9687 5120+/* Copyright (C) 2007 Sven Wegener <sven.wegener@stealer.net>
5121+ *
5122+ * This program is free software; you can redistribute it and/or modify it
5123+ * under the terms of the GNU General Public License version 2 as published by
5124+ * the Free Software Foundation.
5125+ */
5126+
5127+/* This modules implements the iptreemap ipset type. It uses bitmaps to
7d2f026e 5128+ * represent every single IPv4 address as a bit. The bitmaps are managed in a
5129+ * tree structure, where the first three octets of an address are used as an
5130+ * index to find the bitmap and the last octet is used as the bit number.
f45e9687 5131+ */
5132+
5133+#include <linux/version.h>
7d2f026e 5134+#include <linux/kernel.h>
f45e9687 5135+#include <linux/module.h>
5136+#include <linux/ip.h>
5137+#include <linux/skbuff.h>
5138+#include <linux/slab.h>
5139+#include <linux/delay.h>
5140+#include <linux/netfilter_ipv4/ip_tables.h>
5141+#include <linux/netfilter_ipv4/ip_set.h>
5142+#include <linux/errno.h>
5143+#include <asm/uaccess.h>
5144+#include <asm/bitops.h>
5145+#include <linux/spinlock.h>
5146+
5147+#include <linux/netfilter_ipv4/ip_set_iptreemap.h>
5148+
5149+#define IPTREEMAP_DEFAULT_GC_TIME (5 * 60)
5150+#define IPTREEMAP_DESTROY_SLEEP (100)
5151+
5152+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21)
5153+static struct kmem_cache *cachep_b;
5154+static struct kmem_cache *cachep_c;
5155+static struct kmem_cache *cachep_d;
5156+#else
5157+static kmem_cache_t *cachep_b;
5158+static kmem_cache_t *cachep_c;
5159+static kmem_cache_t *cachep_d;
5160+#endif
5161+
5162+static struct ip_set_iptreemap_d *fullbitmap_d;
5163+static struct ip_set_iptreemap_c *fullbitmap_c;
5164+static struct ip_set_iptreemap_b *fullbitmap_b;
5165+
5166+#if defined(__LITTLE_ENDIAN)
5167+#define ABCD(a, b, c, d, addr) \
5168+ do { \
5169+ a = ((unsigned char *)addr)[3]; \
5170+ b = ((unsigned char *)addr)[2]; \
5171+ c = ((unsigned char *)addr)[1]; \
5172+ d = ((unsigned char *)addr)[0]; \
5173+ } while (0)
5174+#elif defined(__BIG_ENDIAN)
5175+#define ABCD(a,b,c,d,addrp) do { \
5176+ a = ((unsigned char *)addrp)[0]; \
5177+ b = ((unsigned char *)addrp)[1]; \
5178+ c = ((unsigned char *)addrp)[2]; \
5179+ d = ((unsigned char *)addrp)[3]; \
5180+} while (0)
5181+#else
5182+#error "Please fix asm/byteorder.h"
5183+#endif /* __LITTLE_ENDIAN */
5184+
5185+#define TESTIP_WALK(map, elem, branch, full) \
5186+ do { \
5187+ branch = (map)->tree[elem]; \
5188+ if (!branch) \
5189+ return 0; \
5190+ else if (branch == full) \
5191+ return 1; \
5192+ } while (0)
5193+
5194+#define ADDIP_WALK(map, elem, branch, type, cachep, full) \
5195+ do { \
5196+ branch = (map)->tree[elem]; \
5197+ if (!branch) { \
5198+ branch = (type *) kmem_cache_alloc(cachep, GFP_ATOMIC); \
5199+ if (!branch) \
5200+ return -ENOMEM; \
5201+ memset(branch, 0, sizeof(*branch)); \
5202+ (map)->tree[elem] = branch; \
5203+ } else if (branch == full) { \
5204+ return -EEXIST; \
5205+ } \
5206+ } while (0)
5207+
5208+#define ADDIP_RANGE_LOOP(map, a, a1, a2, hint, branch, full, cachep, free) \
5209+ for (a = a1; a <= a2; a++) { \
5210+ branch = (map)->tree[a]; \
5211+ if (branch != full) { \
5212+ if ((a > a1 && a < a2) || (hint)) { \
5213+ if (branch) \
5214+ free(branch); \
5215+ (map)->tree[a] = full; \
5216+ continue; \
5217+ } else if (!branch) { \
5218+ branch = kmem_cache_alloc(cachep, GFP_ATOMIC); \
5219+ if (!branch) \
5220+ return -ENOMEM; \
5221+ memset(branch, 0, sizeof(*branch)); \
5222+ (map)->tree[a] = branch; \
5223+ }
5224+
5225+#define ADDIP_RANGE_LOOP_END() \
5226+ } \
5227+ }
5228+
5229+#define DELIP_WALK(map, elem, branch, cachep, full, flags) \
5230+ do { \
5231+ branch = (map)->tree[elem]; \
5232+ if (!branch) { \
5233+ return -EEXIST; \
5234+ } else if (branch == full) { \
5235+ branch = kmem_cache_alloc(cachep, flags); \
5236+ if (!branch) \
5237+ return -ENOMEM; \
5238+ memcpy(branch, full, sizeof(*full)); \
5239+ (map)->tree[elem] = branch; \
5240+ } \
5241+ } while (0)
5242+
5243+#define DELIP_RANGE_LOOP(map, a, a1, a2, hint, branch, full, cachep, free, flags) \
5244+ for (a = a1; a <= a2; a++) { \
5245+ branch = (map)->tree[a]; \
5246+ if (branch) { \
5247+ if ((a > a1 && a < a2) || (hint)) { \
5248+ if (branch != full) \
5249+ free(branch); \
5250+ (map)->tree[a] = NULL; \
5251+ continue; \
5252+ } else if (branch == full) { \
5253+ branch = kmem_cache_alloc(cachep, flags); \
5254+ if (!branch) \
5255+ return -ENOMEM; \
5256+ memcpy(branch, full, sizeof(*branch)); \
5257+ (map)->tree[a] = branch; \
5258+ }
5259+
5260+#define DELIP_RANGE_LOOP_END() \
5261+ } \
5262+ }
5263+
5264+#define LOOP_WALK_BEGIN(map, i, branch) \
5265+ for (i = 0; i < 256; i++) { \
5266+ branch = (map)->tree[i]; \
5267+ if (likely(!branch)) \
5268+ continue;
5269+
5270+#define LOOP_WALK_END() \
5271+ }
5272+
5273+#define LOOP_WALK_BEGIN_GC(map, i, branch, full, cachep, count) \
5274+ count = -256; \
5275+ for (i = 0; i < 256; i++) { \
5276+ branch = (map)->tree[i]; \
5277+ if (likely(!branch)) \
5278+ continue; \
5279+ count++; \
5280+ if (branch == full) { \
5281+ count++; \
5282+ continue; \
5283+ }
5284+
5285+#define LOOP_WALK_END_GC(map, i, branch, full, cachep, count) \
5286+ if (-256 == count) { \
5287+ kmem_cache_free(cachep, branch); \
5288+ (map)->tree[i] = NULL; \
5289+ } else if (256 == count) { \
5290+ kmem_cache_free(cachep, branch); \
5291+ (map)->tree[i] = full; \
5292+ } \
5293+ }
5294+
5295+#define LOOP_WALK_BEGIN_COUNT(map, i, branch, inrange, count) \
5296+ for (i = 0; i < 256; i++) { \
5297+ if (!(map)->tree[i]) { \
5298+ if (inrange) { \
5299+ count++; \
5300+ inrange = 0; \
5301+ } \
5302+ continue; \
5303+ } \
5304+ branch = (map)->tree[i];
5305+
5306+#define LOOP_WALK_END_COUNT() \
5307+ }
5308+
f45e9687 5309+#define GETVALUE1(a, a1, b1, r) \
5310+ (a == a1 ? b1 : r)
5311+
5312+#define GETVALUE2(a, b, a1, b1, c1, r) \
5313+ (a == a1 && b == b1 ? c1 : r)
5314+
5315+#define GETVALUE3(a, b, c, a1, b1, c1, d1, r) \
5316+ (a == a1 && b == b1 && c == c1 ? d1 : r)
5317+
5318+#define CHECK1(a, a1, a2, b1, b2, c1, c2, d1, d2) \
5319+ ( \
5320+ GETVALUE1(a, a1, b1, 0) == 0 \
5321+ && GETVALUE1(a, a2, b2, 255) == 255 \
5322+ && c1 == 0 \
5323+ && c2 == 255 \
5324+ && d1 == 0 \
5325+ && d2 == 255 \
5326+ )
5327+
5328+#define CHECK2(a, b, a1, a2, b1, b2, c1, c2, d1, d2) \
5329+ ( \
5330+ GETVALUE2(a, b, a1, b1, c1, 0) == 0 \
5331+ && GETVALUE2(a, b, a2, b2, c2, 255) == 255 \
5332+ && d1 == 0 \
5333+ && d2 == 255 \
5334+ )
5335+
5336+#define CHECK3(a, b, c, a1, a2, b1, b2, c1, c2, d1, d2) \
5337+ ( \
5338+ GETVALUE3(a, b, c, a1, b1, c1, d1, 0) == 0 \
5339+ && GETVALUE3(a, b, c, a2, b2, c2, d2, 255) == 255 \
5340+ )
5341+
5342+
5343+static inline void
5344+free_d(struct ip_set_iptreemap_d *map)
5345+{
5346+ kmem_cache_free(cachep_d, map);
5347+}
5348+
5349+static inline void
5350+free_c(struct ip_set_iptreemap_c *map)
5351+{
5352+ struct ip_set_iptreemap_d *dtree;
5353+ unsigned int i;
5354+
5355+ LOOP_WALK_BEGIN(map, i, dtree) {
5356+ if (dtree != fullbitmap_d)
5357+ free_d(dtree);
5358+ } LOOP_WALK_END();
5359+
5360+ kmem_cache_free(cachep_c, map);
5361+}
5362+
5363+static inline void
5364+free_b(struct ip_set_iptreemap_b *map)
5365+{
5366+ struct ip_set_iptreemap_c *ctree;
5367+ unsigned int i;
5368+
5369+ LOOP_WALK_BEGIN(map, i, ctree) {
5370+ if (ctree != fullbitmap_c)
5371+ free_c(ctree);
5372+ } LOOP_WALK_END();
5373+
5374+ kmem_cache_free(cachep_b, map);
5375+}
5376+
5377+static inline int
5378+__testip(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip)
5379+{
7d2f026e 5380+ struct ip_set_iptreemap *map = set->data;
f45e9687 5381+ struct ip_set_iptreemap_b *btree;
5382+ struct ip_set_iptreemap_c *ctree;
5383+ struct ip_set_iptreemap_d *dtree;
5384+ unsigned char a, b, c, d;
5385+
5386+ *hash_ip = ip;
5387+
5388+ ABCD(a, b, c, d, hash_ip);
5389+
5390+ TESTIP_WALK(map, a, btree, fullbitmap_b);
5391+ TESTIP_WALK(btree, b, ctree, fullbitmap_c);
5392+ TESTIP_WALK(ctree, c, dtree, fullbitmap_d);
5393+
5394+ return !!test_bit(d, (void *) dtree->bitmap);
5395+}
5396+
5397+static int
5398+testip(struct ip_set *set, const void *data, size_t size, ip_set_ip_t *hash_ip)
5399+{
7d2f026e 5400+ const struct ip_set_req_iptreemap *req = data;
f45e9687 5401+
5402+ if (size != sizeof(struct ip_set_req_iptreemap)) {
5403+ ip_set_printk("data length wrong (want %zu, have %zu)", sizeof(struct ip_set_req_iptreemap), size);
5404+ return -EINVAL;
5405+ }
5406+
5407+ return __testip(set, req->start, hash_ip);
5408+}
5409+
5410+static int
5411+testip_kernel(struct ip_set *set, const struct sk_buff *skb, ip_set_ip_t *hash_ip, const u_int32_t *flags, unsigned char index)
5412+{
5413+ int res;
5414+
7d2f026e 5415+ res = __testip(set,
5416+ ntohl(flags[index] & IPSET_SRC
f45e9687 5417+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
7d2f026e 5418+ ? ip_hdr(skb)->saddr
f45e9687 5419+ : ip_hdr(skb)->daddr),
5420+#else
7d2f026e 5421+ ? skb->nh.iph->saddr
f45e9687 5422+ : skb->nh.iph->daddr),
5423+#endif
5424+ hash_ip);
5425+
5426+ return (res < 0 ? 0 : res);
5427+}
5428+
5429+static inline int
5430+__addip_single(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip)
5431+{
5432+ struct ip_set_iptreemap *map = (struct ip_set_iptreemap *) set->data;
5433+ struct ip_set_iptreemap_b *btree;
5434+ struct ip_set_iptreemap_c *ctree;
5435+ struct ip_set_iptreemap_d *dtree;
5436+ unsigned char a, b, c, d;
5437+
5438+ *hash_ip = ip;
5439+
5440+ ABCD(a, b, c, d, hash_ip);
5441+
5442+ ADDIP_WALK(map, a, btree, struct ip_set_iptreemap_b, cachep_b, fullbitmap_b);
5443+ ADDIP_WALK(btree, b, ctree, struct ip_set_iptreemap_c, cachep_c, fullbitmap_c);
5444+ ADDIP_WALK(ctree, c, dtree, struct ip_set_iptreemap_d, cachep_d, fullbitmap_d);
5445+
7d2f026e 5446+ if (__test_and_set_bit(d, (void *) dtree->bitmap))
f45e9687 5447+ return -EEXIST;
5448+
7d2f026e 5449+ __set_bit(b, (void *) btree->dirty);
f45e9687 5450+
5451+ return 0;
5452+}
5453+
5454+static inline int
5455+__addip_range(struct ip_set *set, ip_set_ip_t start, ip_set_ip_t end, ip_set_ip_t *hash_ip)
5456+{
7d2f026e 5457+ struct ip_set_iptreemap *map = set->data;
f45e9687 5458+ struct ip_set_iptreemap_b *btree;
5459+ struct ip_set_iptreemap_c *ctree;
5460+ struct ip_set_iptreemap_d *dtree;
5461+ unsigned int a, b, c, d;
5462+ unsigned char a1, b1, c1, d1;
5463+ unsigned char a2, b2, c2, d2;
5464+
5465+ if (start == end)
5466+ return __addip_single(set, start, hash_ip);
5467+
5468+ *hash_ip = start;
5469+
5470+ ABCD(a1, b1, c1, d1, &start);
5471+ ABCD(a2, b2, c2, d2, &end);
5472+
5473+ /* This is sooo ugly... */
5474+ ADDIP_RANGE_LOOP(map, a, a1, a2, CHECK1(a, a1, a2, b1, b2, c1, c2, d1, d2), btree, fullbitmap_b, cachep_b, free_b) {
5475+ ADDIP_RANGE_LOOP(btree, b, GETVALUE1(a, a1, b1, 0), GETVALUE1(a, a2, b2, 255), CHECK2(a, b, a1, a2, b1, b2, c1, c2, d1, d2), ctree, fullbitmap_c, cachep_c, free_c) {
5476+ ADDIP_RANGE_LOOP(ctree, c, GETVALUE2(a, b, a1, b1, c1, 0), GETVALUE2(a, b, a2, b2, c2, 255), CHECK3(a, b, c, a1, a2, b1, b2, c1, c2, d1, d2), dtree, fullbitmap_d, cachep_d, free_d) {
5477+ for (d = GETVALUE3(a, b, c, a1, b1, c1, d1, 0); d <= GETVALUE3(a, b, c, a2, b2, c2, d2, 255); d++)
7d2f026e 5478+ __set_bit(d, (void *) dtree->bitmap);
5479+ __set_bit(b, (void *) btree->dirty);
f45e9687 5480+ } ADDIP_RANGE_LOOP_END();
5481+ } ADDIP_RANGE_LOOP_END();
5482+ } ADDIP_RANGE_LOOP_END();
5483+
5484+ return 0;
5485+}
5486+
5487+static int
5488+addip(struct ip_set *set, const void *data, size_t size, ip_set_ip_t *hash_ip)
5489+{
7d2f026e 5490+ const struct ip_set_req_iptreemap *req = data;
f45e9687 5491+
5492+ if (size != sizeof(struct ip_set_req_iptreemap)) {
5493+ ip_set_printk("data length wrong (want %zu, have %zu)", sizeof(struct ip_set_req_iptreemap), size);
5494+ return -EINVAL;
5495+ }
5496+
7d2f026e 5497+ return __addip_range(set, min(req->start, req->end), max(req->start, req->end), hash_ip);
f45e9687 5498+}
5499+
5500+static int
5501+addip_kernel(struct ip_set *set, const struct sk_buff *skb, ip_set_ip_t *hash_ip, const u_int32_t *flags, unsigned char index)
5502+{
5503+
5504+ return __addip_single(set,
7d2f026e 5505+ ntohl(flags[index] & IPSET_SRC
f45e9687 5506+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
7d2f026e 5507+ ? ip_hdr(skb)->saddr
f45e9687 5508+ : ip_hdr(skb)->daddr),
5509+#else
7d2f026e 5510+ ? skb->nh.iph->saddr
f45e9687 5511+ : skb->nh.iph->daddr),
5512+#endif
5513+ hash_ip);
5514+}
5515+
5516+static inline int
5517+__delip_single(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip, unsigned int __nocast flags)
5518+{
7d2f026e 5519+ struct ip_set_iptreemap *map = set->data;
f45e9687 5520+ struct ip_set_iptreemap_b *btree;
5521+ struct ip_set_iptreemap_c *ctree;
5522+ struct ip_set_iptreemap_d *dtree;
5523+ unsigned char a,b,c,d;
5524+
5525+ *hash_ip = ip;
5526+
5527+ ABCD(a, b, c, d, hash_ip);
5528+
5529+ DELIP_WALK(map, a, btree, cachep_b, fullbitmap_b, flags);
5530+ DELIP_WALK(btree, b, ctree, cachep_c, fullbitmap_c, flags);
5531+ DELIP_WALK(ctree, c, dtree, cachep_d, fullbitmap_d, flags);
5532+
7d2f026e 5533+ if (!__test_and_clear_bit(d, (void *) dtree->bitmap))
f45e9687 5534+ return -EEXIST;
5535+
7d2f026e 5536+ __set_bit(b, (void *) btree->dirty);
f45e9687 5537+
5538+ return 0;
5539+}
5540+
5541+static inline int
5542+__delip_range(struct ip_set *set, ip_set_ip_t start, ip_set_ip_t end, ip_set_ip_t *hash_ip, unsigned int __nocast flags)
5543+{
7d2f026e 5544+ struct ip_set_iptreemap *map = set->data;
f45e9687 5545+ struct ip_set_iptreemap_b *btree;
5546+ struct ip_set_iptreemap_c *ctree;
5547+ struct ip_set_iptreemap_d *dtree;
5548+ unsigned int a, b, c, d;
5549+ unsigned char a1, b1, c1, d1;
5550+ unsigned char a2, b2, c2, d2;
5551+
5552+ if (start == end)
5553+ return __delip_single(set, start, hash_ip, flags);
5554+
5555+ *hash_ip = start;
5556+
5557+ ABCD(a1, b1, c1, d1, &start);
5558+ ABCD(a2, b2, c2, d2, &end);
5559+
5560+ /* This is sooo ugly... */
5561+ DELIP_RANGE_LOOP(map, a, a1, a2, CHECK1(a, a1, a2, b1, b2, c1, c2, d1, d2), btree, fullbitmap_b, cachep_b, free_b, flags) {
5562+ DELIP_RANGE_LOOP(btree, b, GETVALUE1(a, a1, b1, 0), GETVALUE1(a, a2, b2, 255), CHECK2(a, b, a1, a2, b1, b2, c1, c2, d1, d2), ctree, fullbitmap_c, cachep_c, free_c, flags) {
5563+ DELIP_RANGE_LOOP(ctree, c, GETVALUE2(a, b, a1, b1, c1, 0), GETVALUE2(a, b, a2, b2, c2, 255), CHECK3(a, b, c, a1, a2, b1, b2, c1, c2, d1, d2), dtree, fullbitmap_d, cachep_d, free_d, flags) {
5564+ for (d = GETVALUE3(a, b, c, a1, b1, c1, d1, 0); d <= GETVALUE3(a, b, c, a2, b2, c2, d2, 255); d++)
7d2f026e 5565+ __clear_bit(d, (void *) dtree->bitmap);
5566+ __set_bit(b, (void *) btree->dirty);
f45e9687 5567+ } DELIP_RANGE_LOOP_END();
5568+ } DELIP_RANGE_LOOP_END();
5569+ } DELIP_RANGE_LOOP_END();
5570+
5571+ return 0;
5572+}
5573+
5574+static int
5575+delip(struct ip_set *set, const void *data, size_t size, ip_set_ip_t *hash_ip)
5576+{
7d2f026e 5577+ const struct ip_set_req_iptreemap *req = data;
f45e9687 5578+
5579+ if (size != sizeof(struct ip_set_req_iptreemap)) {
5580+ ip_set_printk("data length wrong (want %zu, have %zu)", sizeof(struct ip_set_req_iptreemap), size);
5581+ return -EINVAL;
5582+ }
5583+
7d2f026e 5584+ return __delip_range(set, min(req->start, req->end), max(req->start, req->end), hash_ip, GFP_KERNEL);
f45e9687 5585+}
5586+
5587+static int
5588+delip_kernel(struct ip_set *set, const struct sk_buff *skb, ip_set_ip_t *hash_ip, const u_int32_t *flags, unsigned char index)
5589+{
7d2f026e 5590+ return __delip_single(set,
5591+ ntohl(flags[index] & IPSET_SRC
f45e9687 5592+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
7d2f026e 5593+ ? ip_hdr(skb)->saddr
f45e9687 5594+ : ip_hdr(skb)->daddr),
5595+#else
7d2f026e 5596+ ? skb->nh.iph->saddr
f45e9687 5597+ : skb->nh.iph->daddr),
5598+#endif
5599+ hash_ip,
5600+ GFP_ATOMIC);
5601+}
5602+
5603+/* Check the status of the bitmap
5604+ * -1 == all bits cleared
5605+ * 1 == all bits set
5606+ * 0 == anything else
5607+ */
5608+static inline int
5609+bitmap_status(struct ip_set_iptreemap_d *dtree)
5610+{
5611+ unsigned char first = dtree->bitmap[0];
5612+ int a;
5613+
5614+ for (a = 1; a < 32; a++)
5615+ if (dtree->bitmap[a] != first)
5616+ return 0;
5617+
5618+ return (first == 0 ? -1 : (first == 255 ? 1 : 0));
5619+}
5620+
5621+static void
5622+gc(unsigned long addr)
5623+{
5624+ struct ip_set *set = (struct ip_set *) addr;
7d2f026e 5625+ struct ip_set_iptreemap *map = set->data;
f45e9687 5626+ struct ip_set_iptreemap_b *btree;
5627+ struct ip_set_iptreemap_c *ctree;
5628+ struct ip_set_iptreemap_d *dtree;
5629+ unsigned int a, b, c;
5630+ int i, j, k;
5631+
5632+ write_lock_bh(&set->lock);
5633+
5634+ LOOP_WALK_BEGIN_GC(map, a, btree, fullbitmap_b, cachep_b, i) {
5635+ LOOP_WALK_BEGIN_GC(btree, b, ctree, fullbitmap_c, cachep_c, j) {
7d2f026e 5636+ if (!__test_and_clear_bit(b, (void *) btree->dirty))
f45e9687 5637+ continue;
5638+ LOOP_WALK_BEGIN_GC(ctree, c, dtree, fullbitmap_d, cachep_d, k) {
5639+ switch (bitmap_status(dtree)) {
5640+ case -1:
5641+ kmem_cache_free(cachep_d, dtree);
5642+ ctree->tree[c] = NULL;
5643+ k--;
5644+ break;
5645+ case 1:
5646+ kmem_cache_free(cachep_d, dtree);
5647+ ctree->tree[c] = fullbitmap_d;
5648+ k++;
5649+ break;
5650+ }
5651+ } LOOP_WALK_END();
5652+ } LOOP_WALK_END_GC(btree, b, ctree, fullbitmap_c, cachep_c, k);
5653+ } LOOP_WALK_END_GC(map, a, btree, fullbitmap_b, cachep_b, j);
5654+
5655+ write_unlock_bh(&set->lock);
5656+
5657+ map->gc.expires = jiffies + map->gc_interval * HZ;
5658+ add_timer(&map->gc);
5659+}
5660+
5661+static inline void
5662+init_gc_timer(struct ip_set *set)
5663+{
7d2f026e 5664+ struct ip_set_iptreemap *map = set->data;
f45e9687 5665+
5666+ init_timer(&map->gc);
5667+ map->gc.data = (unsigned long) set;
5668+ map->gc.function = gc;
5669+ map->gc.expires = jiffies + map->gc_interval * HZ;
5670+ add_timer(&map->gc);
5671+}
5672+
5673+static int create(struct ip_set *set, const void *data, size_t size)
5674+{
7d2f026e 5675+ const struct ip_set_req_iptreemap_create *req = data;
f45e9687 5676+ struct ip_set_iptreemap *map;
5677+
5678+ if (size != sizeof(struct ip_set_req_iptreemap_create)) {
5679+ ip_set_printk("data length wrong (want %zu, have %zu)", sizeof(struct ip_set_req_iptreemap_create), size);
5680+ return -EINVAL;
5681+ }
5682+
5683+ map = kzalloc(sizeof(*map), GFP_KERNEL);
5684+ if (!map)
5685+ return -ENOMEM;
5686+
5687+ map->gc_interval = req->gc_interval ? req->gc_interval : IPTREEMAP_DEFAULT_GC_TIME;
5688+ set->data = map;
5689+
5690+ init_gc_timer(set);
5691+
5692+ return 0;
5693+}
5694+
5695+static inline void __flush(struct ip_set_iptreemap *map)
5696+{
5697+ struct ip_set_iptreemap_b *btree;
5698+ unsigned int a;
5699+
5700+ LOOP_WALK_BEGIN(map, a, btree);
5701+ if (btree != fullbitmap_b)
5702+ free_b(btree);
5703+ LOOP_WALK_END();
5704+}
5705+
5706+static void destroy(struct ip_set *set)
5707+{
7d2f026e 5708+ struct ip_set_iptreemap *map = set->data;
f45e9687 5709+
5710+ while (!del_timer(&map->gc))
5711+ msleep(IPTREEMAP_DESTROY_SLEEP);
5712+
5713+ __flush(map);
5714+ kfree(map);
5715+
5716+ set->data = NULL;
5717+}
5718+
5719+static void flush(struct ip_set *set)
5720+{
7d2f026e 5721+ struct ip_set_iptreemap *map = set->data;
f45e9687 5722+
5723+ while (!del_timer(&map->gc))
5724+ msleep(IPTREEMAP_DESTROY_SLEEP);
5725+
5726+ __flush(map);
5727+
5728+ memset(map, 0, sizeof(*map));
5729+
5730+ init_gc_timer(set);
5731+}
5732+
5733+static void list_header(const struct ip_set *set, void *data)
5734+{
7d2f026e 5735+ struct ip_set_iptreemap *map = set->data;
5736+ struct ip_set_req_iptreemap_create *header = data;
f45e9687 5737+
5738+ header->gc_interval = map->gc_interval;
5739+}
5740+
5741+static int list_members_size(const struct ip_set *set)
5742+{
7d2f026e 5743+ struct ip_set_iptreemap *map = set->data;
f45e9687 5744+ struct ip_set_iptreemap_b *btree;
5745+ struct ip_set_iptreemap_c *ctree;
5746+ struct ip_set_iptreemap_d *dtree;
5747+ unsigned int a, b, c, d, inrange = 0, count = 0;
5748+
5749+ LOOP_WALK_BEGIN_COUNT(map, a, btree, inrange, count) {
5750+ LOOP_WALK_BEGIN_COUNT(btree, b, ctree, inrange, count) {
5751+ LOOP_WALK_BEGIN_COUNT(ctree, c, dtree, inrange, count) {
5752+ for (d = 0; d < 256; d++) {
5753+ if (test_bit(d, (void *) dtree->bitmap)) {
5754+ inrange = 1;
5755+ } else if (inrange) {
5756+ count++;
5757+ inrange = 0;
5758+ }
5759+ }
5760+ } LOOP_WALK_END_COUNT();
5761+ } LOOP_WALK_END_COUNT();
5762+ } LOOP_WALK_END_COUNT();
5763+
5764+ if (inrange)
5765+ count++;
5766+
5767+ return (count * sizeof(struct ip_set_req_iptreemap));
5768+}
5769+
5770+static inline size_t add_member(void *data, size_t offset, ip_set_ip_t start, ip_set_ip_t end)
5771+{
7d2f026e 5772+ struct ip_set_req_iptreemap *entry = data + offset;
f45e9687 5773+
5774+ entry->start = start;
5775+ entry->end = end;
5776+
5777+ return sizeof(*entry);
5778+}
5779+
5780+static void list_members(const struct ip_set *set, void *data)
5781+{
7d2f026e 5782+ struct ip_set_iptreemap *map = set->data;
f45e9687 5783+ struct ip_set_iptreemap_b *btree;
5784+ struct ip_set_iptreemap_c *ctree;
5785+ struct ip_set_iptreemap_d *dtree;
5786+ unsigned int a, b, c, d, inrange = 0;
5787+ size_t offset = 0;
5788+ ip_set_ip_t start = 0, end = 0, ip;
5789+
5790+ LOOP_WALK_BEGIN(map, a, btree) {
5791+ LOOP_WALK_BEGIN(btree, b, ctree) {
5792+ LOOP_WALK_BEGIN(ctree, c, dtree) {
5793+ for (d = 0; d < 256; d++) {
5794+ if (test_bit(d, (void *) dtree->bitmap)) {
5795+ ip = ((a << 24) | (b << 16) | (c << 8) | d);
5796+ if (!inrange) {
5797+ inrange = 1;
5798+ start = ip;
5799+ } else if (end < ip - 1) {
5800+ offset += add_member(data, offset, start, end);
5801+ start = ip;
5802+ }
5803+ end = ip;
5804+ } else if (inrange) {
5805+ offset += add_member(data, offset, start, end);
5806+ inrange = 0;
5807+ }
5808+ }
5809+ } LOOP_WALK_END();
5810+ } LOOP_WALK_END();
5811+ } LOOP_WALK_END();
5812+
5813+ if (inrange)
5814+ add_member(data, offset, start, end);
5815+}
5816+
5817+static struct ip_set_type ip_set_iptreemap = {
5818+ .typename = SETTYPE_NAME,
5819+ .features = IPSET_TYPE_IP | IPSET_DATA_SINGLE,
5820+ .protocol_version = IP_SET_PROTOCOL_VERSION,
5821+ .create = create,
5822+ .destroy = destroy,
5823+ .flush = flush,
5824+ .reqsize = sizeof(struct ip_set_req_iptreemap),
5825+ .addip = addip,
5826+ .addip_kernel = addip_kernel,
5827+ .delip = delip,
5828+ .delip_kernel = delip_kernel,
5829+ .testip = testip,
5830+ .testip_kernel = testip_kernel,
5831+ .header_size = sizeof(struct ip_set_req_iptreemap_create),
5832+ .list_header = list_header,
5833+ .list_members_size = list_members_size,
5834+ .list_members = list_members,
5835+ .me = THIS_MODULE,
5836+};
5837+
5838+MODULE_LICENSE("GPL");
5839+MODULE_AUTHOR("Sven Wegener <sven.wegener@stealer.net>");
5840+MODULE_DESCRIPTION("iptreemap type of IP sets");
5841+
5842+static int __init ip_set_iptreemap_init(void)
5843+{
5844+ int ret = -ENOMEM;
5845+ int a;
5846+
5847+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,23)
7d2f026e 5848+ cachep_b = kmem_cache_create("ip_set_iptreemap_b",
5849+ sizeof(struct ip_set_iptreemap_b),
f45e9687 5850+ 0, 0, NULL);
5851+#else
7d2f026e 5852+ cachep_b = kmem_cache_create("ip_set_iptreemap_b",
5853+ sizeof(struct ip_set_iptreemap_b),
f45e9687 5854+ 0, 0, NULL, NULL);
5855+#endif
5856+ if (!cachep_b) {
5857+ ip_set_printk("Unable to create ip_set_iptreemap_b slab cache");
5858+ goto out;
5859+ }
5860+
5861+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,23)
7d2f026e 5862+ cachep_c = kmem_cache_create("ip_set_iptreemap_c",
f45e9687 5863+ sizeof(struct ip_set_iptreemap_c),
5864+ 0, 0, NULL);
5865+#else
7d2f026e 5866+ cachep_c = kmem_cache_create("ip_set_iptreemap_c",
f45e9687 5867+ sizeof(struct ip_set_iptreemap_c),
5868+ 0, 0, NULL, NULL);
5869+#endif
5870+ if (!cachep_c) {
5871+ ip_set_printk("Unable to create ip_set_iptreemap_c slab cache");
5872+ goto outb;
5873+ }
5874+
5875+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,23)
5876+ cachep_d = kmem_cache_create("ip_set_iptreemap_d",
5877+ sizeof(struct ip_set_iptreemap_d),
5878+ 0, 0, NULL);
5879+#else
5880+ cachep_d = kmem_cache_create("ip_set_iptreemap_d",
5881+ sizeof(struct ip_set_iptreemap_d),
5882+ 0, 0, NULL, NULL);
5883+#endif
5884+ if (!cachep_d) {
5885+ ip_set_printk("Unable to create ip_set_iptreemap_d slab cache");
5886+ goto outc;
5887+ }
5888+
5889+ fullbitmap_d = kmem_cache_alloc(cachep_d, GFP_KERNEL);
5890+ if (!fullbitmap_d)
5891+ goto outd;
5892+
5893+ fullbitmap_c = kmem_cache_alloc(cachep_c, GFP_KERNEL);
5894+ if (!fullbitmap_c)
5895+ goto outbitmapd;
5896+
5897+ fullbitmap_b = kmem_cache_alloc(cachep_b, GFP_KERNEL);
5898+ if (!fullbitmap_b)
5899+ goto outbitmapc;
5900+
5901+ ret = ip_set_register_set_type(&ip_set_iptreemap);
5902+ if (0 > ret)
5903+ goto outbitmapb;
5904+
5905+ /* Now init our global bitmaps */
5906+ memset(fullbitmap_d->bitmap, 0xff, sizeof(fullbitmap_d->bitmap));
5907+
5908+ for (a = 0; a < 256; a++)
5909+ fullbitmap_c->tree[a] = fullbitmap_d;
5910+
5911+ for (a = 0; a < 256; a++)
5912+ fullbitmap_b->tree[a] = fullbitmap_c;
5913+ memset(fullbitmap_b->dirty, 0, sizeof(fullbitmap_b->dirty));
5914+
5915+ return 0;
5916+
5917+outbitmapb:
5918+ kmem_cache_free(cachep_b, fullbitmap_b);
5919+outbitmapc:
5920+ kmem_cache_free(cachep_c, fullbitmap_c);
5921+outbitmapd:
5922+ kmem_cache_free(cachep_d, fullbitmap_d);
5923+outd:
5924+ kmem_cache_destroy(cachep_d);
5925+outc:
5926+ kmem_cache_destroy(cachep_c);
5927+outb:
5928+ kmem_cache_destroy(cachep_b);
5929+out:
5930+
5931+ return ret;
5932+}
5933+
5934+static void __exit ip_set_iptreemap_fini(void)
5935+{
5936+ ip_set_unregister_set_type(&ip_set_iptreemap);
5937+ kmem_cache_free(cachep_d, fullbitmap_d);
5938+ kmem_cache_free(cachep_c, fullbitmap_c);
5939+ kmem_cache_free(cachep_b, fullbitmap_b);
5940+ kmem_cache_destroy(cachep_d);
5941+ kmem_cache_destroy(cachep_c);
5942+ kmem_cache_destroy(cachep_b);
5943+}
5944+
5945+module_init(ip_set_iptreemap_init);
5946+module_exit(ip_set_iptreemap_fini);
7d2f026e 5947diff -uNrp --exclude=.svn a/net/ipv4/netfilter/ip_set_macipmap.c linux-2.6/net/ipv4/netfilter/ip_set_macipmap.c
5948--- a/net/ipv4/netfilter/ip_set_macipmap.c 1970-01-01 01:00:00.000000000 +0100
5949+++ linux-2.6/net/ipv4/netfilter/ip_set_macipmap.c 2008-07-08 16:52:53.965201208 +0200
5950@@ -0,0 +1,360 @@
1aedc22c 5951+/* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu>
5952+ * Patrick Schaaf <bof@bof.de>
5953+ * Martin Josefsson <gandalf@wlug.westbo.se>
5954+ * Copyright (C) 2003-2004 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
5955+ *
5956+ * This program is free software; you can redistribute it and/or modify
5957+ * it under the terms of the GNU General Public License version 2 as
7d2f026e 5958+ * published by the Free Software Foundation.
1aedc22c 5959+ */
5960+
5961+/* Kernel module implementing an IP set type: the macipmap type */
5962+
5963+#include <linux/module.h>
5964+#include <linux/ip.h>
5965+#include <linux/skbuff.h>
f45e9687 5966+#include <linux/version.h>
1aedc22c 5967+#include <linux/netfilter_ipv4/ip_tables.h>
5968+#include <linux/netfilter_ipv4/ip_set.h>
5969+#include <linux/errno.h>
5970+#include <asm/uaccess.h>
5971+#include <asm/bitops.h>
5972+#include <linux/spinlock.h>
5973+#include <linux/if_ether.h>
5974+#include <linux/vmalloc.h>
5975+
5976+#include <linux/netfilter_ipv4/ip_set_malloc.h>
5977+#include <linux/netfilter_ipv4/ip_set_macipmap.h>
5978+
5979+static int
5980+testip(struct ip_set *set, const void *data, size_t size, ip_set_ip_t *hash_ip)
5981+{
7d2f026e 5982+ struct ip_set_macipmap *map = set->data;
5983+ struct ip_set_macip *table = map->members;
5984+ const struct ip_set_req_macipmap *req = data;
1aedc22c 5985+
5986+ if (size != sizeof(struct ip_set_req_macipmap)) {
5987+ ip_set_printk("data length wrong (want %zu, have %zu)",
5988+ sizeof(struct ip_set_req_macipmap),
5989+ size);
5990+ return -EINVAL;
5991+ }
5992+
5993+ if (req->ip < map->first_ip || req->ip > map->last_ip)
5994+ return -ERANGE;
5995+
5996+ *hash_ip = req->ip;
5997+ DP("set: %s, ip:%u.%u.%u.%u, %u.%u.%u.%u",
5998+ set->name, HIPQUAD(req->ip), HIPQUAD(*hash_ip));
5999+ if (test_bit(IPSET_MACIP_ISSET,
6000+ (void *) &table[req->ip - map->first_ip].flags)) {
6001+ return (memcmp(req->ethernet,
6002+ &table[req->ip - map->first_ip].ethernet,
6003+ ETH_ALEN) == 0);
6004+ } else {
6005+ return (map->flags & IPSET_MACIP_MATCHUNSET ? 1 : 0);
6006+ }
6007+}
6008+
6009+static int
7d2f026e 6010+testip_kernel(struct ip_set *set,
1aedc22c 6011+ const struct sk_buff *skb,
6012+ ip_set_ip_t *hash_ip,
6013+ const u_int32_t *flags,
6014+ unsigned char index)
6015+{
7d2f026e 6016+ struct ip_set_macipmap *map = set->data;
6017+ struct ip_set_macip *table = map->members;
1aedc22c 6018+ ip_set_ip_t ip;
6019+
6020+ ip = ntohl(flags[index] & IPSET_SRC
f45e9687 6021+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
7d2f026e 6022+ ? ip_hdr(skb)->saddr
5ce52adc 6023+ : ip_hdr(skb)->daddr);
f45e9687 6024+#else
6025+ ? skb->nh.iph->saddr
6026+ : skb->nh.iph->daddr);
6027+#endif
1aedc22c 6028+
6029+ if (ip < map->first_ip || ip > map->last_ip)
6030+ return 0;
6031+
6032+ *hash_ip = ip;
6033+ DP("set: %s, ip:%u.%u.%u.%u, %u.%u.%u.%u",
6034+ set->name, HIPQUAD(ip), HIPQUAD(*hash_ip));
6035+ if (test_bit(IPSET_MACIP_ISSET,
6036+ (void *) &table[ip - map->first_ip].flags)) {
6037+ /* Is mac pointer valid?
6038+ * If so, compare... */
f45e9687 6039+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
6040+ return (skb_mac_header(skb) >= skb->head
6041+ && (skb_mac_header(skb) + ETH_HLEN) <= skb->data
6042+#else
6043+ return (skb->mac.raw >= skb->head
6044+ && (skb->mac.raw + ETH_HLEN) <= skb->data
6045+#endif
1aedc22c 6046+ && (memcmp(eth_hdr(skb)->h_source,
6047+ &table[ip - map->first_ip].ethernet,
6048+ ETH_ALEN) == 0));
6049+ } else {
6050+ return (map->flags & IPSET_MACIP_MATCHUNSET ? 1 : 0);
6051+ }
6052+}
6053+
6054+/* returns 0 on success */
6055+static inline int
7d2f026e 6056+__addip(struct ip_set *set,
6057+ ip_set_ip_t ip, const unsigned char *ethernet, ip_set_ip_t *hash_ip)
1aedc22c 6058+{
7d2f026e 6059+ struct ip_set_macipmap *map = set->data;
6060+ struct ip_set_macip *table = map->members;
1aedc22c 6061+
6062+ if (ip < map->first_ip || ip > map->last_ip)
6063+ return -ERANGE;
7d2f026e 6064+ if (test_and_set_bit(IPSET_MACIP_ISSET,
1aedc22c 6065+ (void *) &table[ip - map->first_ip].flags))
6066+ return -EEXIST;
6067+
6068+ *hash_ip = ip;
6069+ DP("%u.%u.%u.%u, %u.%u.%u.%u", HIPQUAD(ip), HIPQUAD(*hash_ip));
6070+ memcpy(&table[ip - map->first_ip].ethernet, ethernet, ETH_ALEN);
6071+ return 0;
6072+}
6073+
6074+static int
6075+addip(struct ip_set *set, const void *data, size_t size,
6076+ ip_set_ip_t *hash_ip)
6077+{
7d2f026e 6078+ const struct ip_set_req_macipmap *req = data;
1aedc22c 6079+
6080+ if (size != sizeof(struct ip_set_req_macipmap)) {
6081+ ip_set_printk("data length wrong (want %zu, have %zu)",
6082+ sizeof(struct ip_set_req_macipmap),
6083+ size);
6084+ return -EINVAL;
6085+ }
6086+ return __addip(set, req->ip, req->ethernet, hash_ip);
6087+}
6088+
6089+static int
7d2f026e 6090+addip_kernel(struct ip_set *set,
1aedc22c 6091+ const struct sk_buff *skb,
6092+ ip_set_ip_t *hash_ip,
6093+ const u_int32_t *flags,
6094+ unsigned char index)
6095+{
6096+ ip_set_ip_t ip;
6097+
6098+ ip = ntohl(flags[index] & IPSET_SRC
f45e9687 6099+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
7d2f026e 6100+ ? ip_hdr(skb)->saddr
5ce52adc 6101+ : ip_hdr(skb)->daddr);
f45e9687 6102+#else
6103+ ? skb->nh.iph->saddr
6104+ : skb->nh.iph->daddr);
6105+#endif
1aedc22c 6106+
f45e9687 6107+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
6108+ if (!(skb_mac_header(skb) >= skb->head
6109+ && (skb_mac_header(skb) + ETH_HLEN) <= skb->data))
6110+#else
6111+ if (!(skb->mac.raw >= skb->head
6112+ && (skb->mac.raw + ETH_HLEN) <= skb->data))
6113+#endif
1aedc22c 6114+ return -EINVAL;
6115+
6116+ return __addip(set, ip, eth_hdr(skb)->h_source, hash_ip);
6117+}
6118+
6119+static inline int
6120+__delip(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip)
6121+{
7d2f026e 6122+ struct ip_set_macipmap *map = set->data;
6123+ struct ip_set_macip *table = map->members;
1aedc22c 6124+
6125+ if (ip < map->first_ip || ip > map->last_ip)
6126+ return -ERANGE;
7d2f026e 6127+ if (!test_and_clear_bit(IPSET_MACIP_ISSET,
1aedc22c 6128+ (void *)&table[ip - map->first_ip].flags))
6129+ return -EEXIST;
6130+
6131+ *hash_ip = ip;
6132+ DP("%u.%u.%u.%u, %u.%u.%u.%u", HIPQUAD(ip), HIPQUAD(*hash_ip));
6133+ return 0;
6134+}
6135+
6136+static int
6137+delip(struct ip_set *set, const void *data, size_t size,
6138+ ip_set_ip_t *hash_ip)
6139+{
7d2f026e 6140+ const struct ip_set_req_macipmap *req = data;
1aedc22c 6141+
6142+ if (size != sizeof(struct ip_set_req_macipmap)) {
6143+ ip_set_printk("data length wrong (want %zu, have %zu)",
6144+ sizeof(struct ip_set_req_macipmap),
6145+ size);
6146+ return -EINVAL;
6147+ }
6148+ return __delip(set, req->ip, hash_ip);
6149+}
6150+
6151+static int
6152+delip_kernel(struct ip_set *set,
6153+ const struct sk_buff *skb,
6154+ ip_set_ip_t *hash_ip,
6155+ const u_int32_t *flags,
6156+ unsigned char index)
6157+{
6158+ return __delip(set,
7d2f026e 6159+ ntohl(flags[index] & IPSET_SRC
f45e9687 6160+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
7d2f026e 6161+ ? ip_hdr(skb)->saddr
5ce52adc 6162+ : ip_hdr(skb)->daddr),
f45e9687 6163+#else
7d2f026e 6164+ ? skb->nh.iph->saddr
f45e9687 6165+ : skb->nh.iph->daddr),
6166+#endif
1aedc22c 6167+ hash_ip);
6168+}
6169+
7d2f026e 6170+static inline size_t members_size(ip_set_ip_t from, ip_set_ip_t to)
1aedc22c 6171+{
6172+ return (size_t)((to - from + 1) * sizeof(struct ip_set_macip));
6173+}
6174+
6175+static int create(struct ip_set *set, const void *data, size_t size)
6176+{
7d2f026e 6177+ size_t newbytes;
6178+ const struct ip_set_req_macipmap_create *req = data;
1aedc22c 6179+ struct ip_set_macipmap *map;
6180+
6181+ if (size != sizeof(struct ip_set_req_macipmap_create)) {
6182+ ip_set_printk("data length wrong (want %zu, have %zu)",
6183+ sizeof(struct ip_set_req_macipmap_create),
6184+ size);
6185+ return -EINVAL;
6186+ }
6187+
6188+ DP("from %u.%u.%u.%u to %u.%u.%u.%u",
6189+ HIPQUAD(req->from), HIPQUAD(req->to));
6190+
6191+ if (req->from > req->to) {
6192+ DP("bad ip range");
6193+ return -ENOEXEC;
6194+ }
6195+
6196+ if (req->to - req->from > MAX_RANGE) {
6197+ ip_set_printk("range too big (max %d addresses)",
6198+ MAX_RANGE+1);
6199+ return -ENOEXEC;
6200+ }
6201+
6202+ map = kmalloc(sizeof(struct ip_set_macipmap), GFP_KERNEL);
6203+ if (!map) {
6204+ DP("out of memory for %d bytes",
6205+ sizeof(struct ip_set_macipmap));
6206+ return -ENOMEM;
6207+ }
6208+ map->flags = req->flags;
6209+ map->first_ip = req->from;
6210+ map->last_ip = req->to;
6211+ newbytes = members_size(map->first_ip, map->last_ip);
6212+ map->members = ip_set_malloc(newbytes);
6213+ DP("members: %u %p", newbytes, map->members);
6214+ if (!map->members) {
6215+ DP("out of memory for %d bytes", newbytes);
6216+ kfree(map);
6217+ return -ENOMEM;
6218+ }
6219+ memset(map->members, 0, newbytes);
6220+
6221+ set->data = map;
6222+ return 0;
6223+}
6224+
6225+static void destroy(struct ip_set *set)
6226+{
7d2f026e 6227+ struct ip_set_macipmap *map = set->data;
1aedc22c 6228+
6229+ ip_set_free(map->members, members_size(map->first_ip, map->last_ip));
6230+ kfree(map);
6231+
6232+ set->data = NULL;
6233+}
6234+
6235+static void flush(struct ip_set *set)
6236+{
7d2f026e 6237+ struct ip_set_macipmap *map = set->data;
1aedc22c 6238+ memset(map->members, 0, members_size(map->first_ip, map->last_ip));
6239+}
6240+
6241+static void list_header(const struct ip_set *set, void *data)
6242+{
7d2f026e 6243+ const struct ip_set_macipmap *map = set->data;
6244+ struct ip_set_req_macipmap_create *header = data;
1aedc22c 6245+
6246+ DP("list_header %x %x %u", map->first_ip, map->last_ip,
6247+ map->flags);
6248+
6249+ header->from = map->first_ip;
6250+ header->to = map->last_ip;
6251+ header->flags = map->flags;
6252+}
6253+
6254+static int list_members_size(const struct ip_set *set)
6255+{
7d2f026e 6256+ const struct ip_set_macipmap *map = set->data;
1aedc22c 6257+
6258+ DP("%u", members_size(map->first_ip, map->last_ip));
6259+ return members_size(map->first_ip, map->last_ip);
6260+}
6261+
6262+static void list_members(const struct ip_set *set, void *data)
6263+{
7d2f026e 6264+ const struct ip_set_macipmap *map = set->data;
1aedc22c 6265+
6266+ int bytes = members_size(map->first_ip, map->last_ip);
6267+
6268+ DP("members: %u %p", bytes, map->members);
6269+ memcpy(data, map->members, bytes);
6270+}
6271+
6272+static struct ip_set_type ip_set_macipmap = {
6273+ .typename = SETTYPE_NAME,
6274+ .features = IPSET_TYPE_IP | IPSET_DATA_SINGLE,
6275+ .protocol_version = IP_SET_PROTOCOL_VERSION,
6276+ .create = &create,
6277+ .destroy = &destroy,
6278+ .flush = &flush,
6279+ .reqsize = sizeof(struct ip_set_req_macipmap),
6280+ .addip = &addip,
6281+ .addip_kernel = &addip_kernel,
6282+ .delip = &delip,
6283+ .delip_kernel = &delip_kernel,
6284+ .testip = &testip,
6285+ .testip_kernel = &testip_kernel,
6286+ .header_size = sizeof(struct ip_set_req_macipmap_create),
6287+ .list_header = &list_header,
6288+ .list_members_size = &list_members_size,
6289+ .list_members = &list_members,
6290+ .me = THIS_MODULE,
6291+};
6292+
6293+MODULE_LICENSE("GPL");
6294+MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
6295+MODULE_DESCRIPTION("macipmap type of IP sets");
6296+
f45e9687 6297+static int __init ip_set_macipmap_init(void)
1aedc22c 6298+{
7d2f026e 6299+ init_max_page_size();
1aedc22c 6300+ return ip_set_register_set_type(&ip_set_macipmap);
6301+}
6302+
f45e9687 6303+static void __exit ip_set_macipmap_fini(void)
1aedc22c 6304+{
6305+ /* FIXME: possible race with ip_set_create() */
6306+ ip_set_unregister_set_type(&ip_set_macipmap);
6307+}
6308+
f45e9687 6309+module_init(ip_set_macipmap_init);
6310+module_exit(ip_set_macipmap_fini);
7d2f026e 6311diff -uNrp --exclude=.svn a/net/ipv4/netfilter/ip_set_nethash.c linux-2.6/net/ipv4/netfilter/ip_set_nethash.c
6312--- a/net/ipv4/netfilter/ip_set_nethash.c 1970-01-01 01:00:00.000000000 +0100
6313+++ linux-2.6/net/ipv4/netfilter/ip_set_nethash.c 2008-07-08 16:52:53.965201208 +0200
6314@@ -0,0 +1,490 @@
1aedc22c 6315+/* Copyright (C) 2003-2004 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
6316+ *
6317+ * This program is free software; you can redistribute it and/or modify
6318+ * it under the terms of the GNU General Public License version 2 as
7d2f026e 6319+ * published by the Free Software Foundation.
1aedc22c 6320+ */
6321+
6322+/* Kernel module implementing a cidr nethash set */
6323+
6324+#include <linux/module.h>
6325+#include <linux/ip.h>
6326+#include <linux/skbuff.h>
f45e9687 6327+#include <linux/version.h>
6328+#include <linux/jhash.h>
1aedc22c 6329+#include <linux/netfilter_ipv4/ip_tables.h>
6330+#include <linux/netfilter_ipv4/ip_set.h>
6331+#include <linux/errno.h>
6332+#include <asm/uaccess.h>
6333+#include <asm/bitops.h>
6334+#include <linux/spinlock.h>
6335+#include <linux/vmalloc.h>
6336+#include <linux/random.h>
6337+
6338+#include <net/ip.h>
6339+
6340+#include <linux/netfilter_ipv4/ip_set_malloc.h>
6341+#include <linux/netfilter_ipv4/ip_set_nethash.h>
1aedc22c 6342+
6343+static int limit = MAX_RANGE;
6344+
6345+static inline __u32
6346+jhash_ip(const struct ip_set_nethash *map, uint16_t i, ip_set_ip_t ip)
6347+{
6348+ return jhash_1word(ip, *(((uint32_t *) map->initval) + i));
6349+}
6350+
6351+static inline __u32
6352+hash_id_cidr(struct ip_set_nethash *map,
6353+ ip_set_ip_t ip,
6354+ unsigned char cidr,
6355+ ip_set_ip_t *hash_ip)
6356+{
6357+ __u32 id;
6358+ u_int16_t i;
6359+ ip_set_ip_t *elem;
6360+
6361+ *hash_ip = pack(ip, cidr);
6362+
6363+ for (i = 0; i < map->probes; i++) {
6364+ id = jhash_ip(map, i, *hash_ip) % map->hashsize;
6365+ DP("hash key: %u", id);
6366+ elem = HARRAY_ELEM(map->members, ip_set_ip_t *, id);
6367+ if (*elem == *hash_ip)
6368+ return id;
6369+ }
6370+ return UINT_MAX;
6371+}
6372+
6373+static inline __u32
6374+hash_id(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip)
6375+{
7d2f026e 6376+ struct ip_set_nethash *map = set->data;
1aedc22c 6377+ __u32 id = UINT_MAX;
6378+ int i;
6379+
6380+ for (i = 0; i < 30 && map->cidr[i]; i++) {
6381+ id = hash_id_cidr(map, ip, map->cidr[i], hash_ip);
6382+ if (id != UINT_MAX)
6383+ break;
6384+ }
6385+ return id;
6386+}
6387+
6388+static inline int
6389+__testip_cidr(struct ip_set *set, ip_set_ip_t ip, unsigned char cidr,
6390+ ip_set_ip_t *hash_ip)
6391+{
7d2f026e 6392+ struct ip_set_nethash *map = set->data;
1aedc22c 6393+
6394+ return (ip && hash_id_cidr(map, ip, cidr, hash_ip) != UINT_MAX);
6395+}
6396+
6397+static inline int
6398+__testip(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip)
6399+{
6400+ return (ip && hash_id(set, ip, hash_ip) != UINT_MAX);
6401+}
6402+
6403+static int
6404+testip(struct ip_set *set, const void *data, size_t size,
6405+ ip_set_ip_t *hash_ip)
6406+{
7d2f026e 6407+ const struct ip_set_req_nethash *req = data;
1aedc22c 6408+
6409+ if (size != sizeof(struct ip_set_req_nethash)) {
6410+ ip_set_printk("data length wrong (want %zu, have %zu)",
6411+ sizeof(struct ip_set_req_nethash),
6412+ size);
6413+ return -EINVAL;
6414+ }
6415+ return (req->cidr == 32 ? __testip(set, req->ip, hash_ip)
6416+ : __testip_cidr(set, req->ip, req->cidr, hash_ip));
6417+}
6418+
6419+static int
7d2f026e 6420+testip_kernel(struct ip_set *set,
1aedc22c 6421+ const struct sk_buff *skb,
6422+ ip_set_ip_t *hash_ip,
6423+ const u_int32_t *flags,
6424+ unsigned char index)
6425+{
6426+ return __testip(set,
7d2f026e 6427+ ntohl(flags[index] & IPSET_SRC
f45e9687 6428+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
7d2f026e 6429+ ? ip_hdr(skb)->saddr
5ce52adc 6430+ : ip_hdr(skb)->daddr),
f45e9687 6431+#else
7d2f026e 6432+ ? skb->nh.iph->saddr
f45e9687 6433+ : skb->nh.iph->daddr),
6434+#endif
1aedc22c 6435+ hash_ip);
6436+}
6437+
6438+static inline int
6439+__addip_base(struct ip_set_nethash *map, ip_set_ip_t ip)
6440+{
6441+ __u32 probe;
6442+ u_int16_t i;
6443+ ip_set_ip_t *elem;
6444+
6445+ for (i = 0; i < map->probes; i++) {
6446+ probe = jhash_ip(map, i, ip) % map->hashsize;
6447+ elem = HARRAY_ELEM(map->members, ip_set_ip_t *, probe);
6448+ if (*elem == ip)
6449+ return -EEXIST;
6450+ if (!*elem) {
6451+ *elem = ip;
6452+ map->elements++;
6453+ return 0;
6454+ }
6455+ }
6456+ /* Trigger rehashing */
6457+ return -EAGAIN;
6458+}
6459+
6460+static inline int
6461+__addip(struct ip_set_nethash *map, ip_set_ip_t ip, unsigned char cidr,
6462+ ip_set_ip_t *hash_ip)
6463+{
f45e9687 6464+ if (!ip || map->elements >= limit)
1aedc22c 6465+ return -ERANGE;
6466+
6467+ *hash_ip = pack(ip, cidr);
6468+ DP("%u.%u.%u.%u/%u, %u.%u.%u.%u", HIPQUAD(ip), cidr, HIPQUAD(*hash_ip));
6469+
6470+ return __addip_base(map, *hash_ip);
6471+}
6472+
6473+static void
6474+update_cidr_sizes(struct ip_set_nethash *map, unsigned char cidr)
6475+{
6476+ unsigned char next;
6477+ int i;
6478+
6479+ for (i = 0; i < 30 && map->cidr[i]; i++) {
6480+ if (map->cidr[i] == cidr) {
6481+ return;
6482+ } else if (map->cidr[i] < cidr) {
6483+ next = map->cidr[i];
6484+ map->cidr[i] = cidr;
6485+ cidr = next;
6486+ }
6487+ }
6488+ if (i < 30)
6489+ map->cidr[i] = cidr;
6490+}
6491+
6492+static int
6493+addip(struct ip_set *set, const void *data, size_t size,
6494+ ip_set_ip_t *hash_ip)
6495+{
7d2f026e 6496+ const struct ip_set_req_nethash *req = data;
1aedc22c 6497+ int ret;
6498+
6499+ if (size != sizeof(struct ip_set_req_nethash)) {
6500+ ip_set_printk("data length wrong (want %zu, have %zu)",
6501+ sizeof(struct ip_set_req_nethash),
6502+ size);
6503+ return -EINVAL;
6504+ }
7d2f026e 6505+ ret = __addip(set->data, req->ip, req->cidr, hash_ip);
1aedc22c 6506+
6507+ if (ret == 0)
7d2f026e 6508+ update_cidr_sizes(set->data, req->cidr);
1aedc22c 6509+
6510+ return ret;
6511+}
6512+
6513+static int
7d2f026e 6514+addip_kernel(struct ip_set *set,
1aedc22c 6515+ const struct sk_buff *skb,
6516+ ip_set_ip_t *hash_ip,
6517+ const u_int32_t *flags,
6518+ unsigned char index)
6519+{
7d2f026e 6520+ struct ip_set_nethash *map = set->data;
1aedc22c 6521+ int ret = -ERANGE;
7d2f026e 6522+ ip_set_ip_t ip = ntohl(flags[index] & IPSET_SRC
f45e9687 6523+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
7d2f026e 6524+ ? ip_hdr(skb)->saddr
5ce52adc 6525+ : ip_hdr(skb)->daddr);
f45e9687 6526+#else
6527+ ? skb->nh.iph->saddr
6528+ : skb->nh.iph->daddr);
6529+#endif
1aedc22c 6530+
6531+ if (map->cidr[0])
6532+ ret = __addip(map, ip, map->cidr[0], hash_ip);
6533+
6534+ return ret;
6535+}
6536+
6537+static int retry(struct ip_set *set)
6538+{
7d2f026e 6539+ struct ip_set_nethash *map = set->data;
1aedc22c 6540+ ip_set_ip_t *elem;
6541+ void *members;
6542+ u_int32_t i, hashsize = map->hashsize;
6543+ int res;
6544+ struct ip_set_nethash *tmp;
6545+
6546+ if (map->resize == 0)
6547+ return -ERANGE;
6548+
6549+ again:
6550+ res = 0;
6551+
6552+ /* Calculate new parameters */
6553+ hashsize += (hashsize * map->resize)/100;
6554+ if (hashsize == map->hashsize)
6555+ hashsize++;
6556+
6557+ ip_set_printk("rehashing of set %s triggered: "
6558+ "hashsize grows from %u to %u",
6559+ set->name, map->hashsize, hashsize);
6560+
7d2f026e 6561+ tmp = kmalloc(sizeof(struct ip_set_nethash)
1aedc22c 6562+ + map->probes * sizeof(uint32_t), GFP_ATOMIC);
6563+ if (!tmp) {
6564+ DP("out of memory for %d bytes",
6565+ sizeof(struct ip_set_nethash)
6566+ + map->probes * sizeof(uint32_t));
6567+ return -ENOMEM;
6568+ }
6569+ tmp->members = harray_malloc(hashsize, sizeof(ip_set_ip_t), GFP_ATOMIC);
6570+ if (!tmp->members) {
6571+ DP("out of memory for %d bytes", hashsize * sizeof(ip_set_ip_t));
6572+ kfree(tmp);
6573+ return -ENOMEM;
6574+ }
6575+ tmp->hashsize = hashsize;
6576+ tmp->elements = 0;
6577+ tmp->probes = map->probes;
6578+ tmp->resize = map->resize;
6579+ memcpy(tmp->initval, map->initval, map->probes * sizeof(uint32_t));
6580+ memcpy(tmp->cidr, map->cidr, 30 * sizeof(unsigned char));
6581+
6582+ write_lock_bh(&set->lock);
7d2f026e 6583+ map = set->data; /* Play safe */
1aedc22c 6584+ for (i = 0; i < map->hashsize && res == 0; i++) {
6585+ elem = HARRAY_ELEM(map->members, ip_set_ip_t *, i);
6586+ if (*elem)
6587+ res = __addip_base(tmp, *elem);
6588+ }
6589+ if (res) {
6590+ /* Failure, try again */
6591+ write_unlock_bh(&set->lock);
6592+ harray_free(tmp->members);
6593+ kfree(tmp);
6594+ goto again;
6595+ }
6596+
6597+ /* Success at resizing! */
6598+ members = map->members;
6599+
6600+ map->hashsize = tmp->hashsize;
6601+ map->members = tmp->members;
6602+ write_unlock_bh(&set->lock);
6603+
6604+ harray_free(members);
6605+ kfree(tmp);
6606+
6607+ return 0;
6608+}
6609+
6610+static inline int
6611+__delip(struct ip_set_nethash *map, ip_set_ip_t ip, unsigned char cidr,
6612+ ip_set_ip_t *hash_ip)
6613+{
6614+ ip_set_ip_t id, *elem;
6615+
6616+ if (!ip)
6617+ return -ERANGE;
6618+
6619+ id = hash_id_cidr(map, ip, cidr, hash_ip);
6620+ if (id == UINT_MAX)
6621+ return -EEXIST;
6622+
6623+ elem = HARRAY_ELEM(map->members, ip_set_ip_t *, id);
6624+ *elem = 0;
6625+ map->elements--;
6626+ return 0;
6627+}
6628+
6629+static int
6630+delip(struct ip_set *set, const void *data, size_t size,
6631+ ip_set_ip_t *hash_ip)
6632+{
7d2f026e 6633+ const struct ip_set_req_nethash *req = data;
1aedc22c 6634+
6635+ if (size != sizeof(struct ip_set_req_nethash)) {
6636+ ip_set_printk("data length wrong (want %zu, have %zu)",
6637+ sizeof(struct ip_set_req_nethash),
6638+ size);
6639+ return -EINVAL;
6640+ }
6641+ /* TODO: no garbage collection in map->cidr */
7d2f026e 6642+ return __delip(set->data, req->ip, req->cidr, hash_ip);
1aedc22c 6643+}
6644+
6645+static int
7d2f026e 6646+delip_kernel(struct ip_set *set,
1aedc22c 6647+ const struct sk_buff *skb,
6648+ ip_set_ip_t *hash_ip,
6649+ const u_int32_t *flags,
6650+ unsigned char index)
6651+{
7d2f026e 6652+ struct ip_set_nethash *map = set->data;
1aedc22c 6653+ int ret = -ERANGE;
7d2f026e 6654+ ip_set_ip_t ip = ntohl(flags[index] & IPSET_SRC
f45e9687 6655+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
7d2f026e 6656+ ? ip_hdr(skb)->saddr
5ce52adc 6657+ : ip_hdr(skb)->daddr);
f45e9687 6658+#else
6659+ ? skb->nh.iph->saddr
6660+ : skb->nh.iph->daddr);
6661+#endif
1aedc22c 6662+
6663+ if (map->cidr[0])
6664+ ret = __delip(map, ip, map->cidr[0], hash_ip);
6665+
6666+ return ret;
6667+}
6668+
6669+static int create(struct ip_set *set, const void *data, size_t size)
6670+{
7d2f026e 6671+ const struct ip_set_req_nethash_create *req = data;
1aedc22c 6672+ struct ip_set_nethash *map;
6673+ uint16_t i;
6674+
6675+ if (size != sizeof(struct ip_set_req_nethash_create)) {
6676+ ip_set_printk("data length wrong (want %zu, have %zu)",
6677+ sizeof(struct ip_set_req_nethash_create),
6678+ size);
6679+ return -EINVAL;
6680+ }
6681+
6682+ if (req->hashsize < 1) {
6683+ ip_set_printk("hashsize too small");
6684+ return -ENOEXEC;
6685+ }
6686+ if (req->probes < 1) {
6687+ ip_set_printk("probes too small");
6688+ return -ENOEXEC;
6689+ }
6690+
6691+ map = kmalloc(sizeof(struct ip_set_nethash)
6692+ + req->probes * sizeof(uint32_t), GFP_KERNEL);
6693+ if (!map) {
6694+ DP("out of memory for %d bytes",
6695+ sizeof(struct ip_set_nethash)
6696+ + req->probes * sizeof(uint32_t));
6697+ return -ENOMEM;
6698+ }
6699+ for (i = 0; i < req->probes; i++)
6700+ get_random_bytes(((uint32_t *) map->initval)+i, 4);
6701+ map->elements = 0;
6702+ map->hashsize = req->hashsize;
6703+ map->probes = req->probes;
6704+ map->resize = req->resize;
6705+ memset(map->cidr, 0, 30 * sizeof(unsigned char));
6706+ map->members = harray_malloc(map->hashsize, sizeof(ip_set_ip_t), GFP_KERNEL);
6707+ if (!map->members) {
6708+ DP("out of memory for %d bytes", map->hashsize * sizeof(ip_set_ip_t));
6709+ kfree(map);
6710+ return -ENOMEM;
6711+ }
6712+
6713+ set->data = map;
6714+ return 0;
6715+}
6716+
6717+static void destroy(struct ip_set *set)
6718+{
7d2f026e 6719+ struct ip_set_nethash *map = set->data;
1aedc22c 6720+
6721+ harray_free(map->members);
6722+ kfree(map);
6723+
6724+ set->data = NULL;
6725+}
6726+
6727+static void flush(struct ip_set *set)
6728+{
7d2f026e 6729+ struct ip_set_nethash *map = set->data;
1aedc22c 6730+ harray_flush(map->members, map->hashsize, sizeof(ip_set_ip_t));
6731+ memset(map->cidr, 0, 30 * sizeof(unsigned char));
6732+ map->elements = 0;
6733+}
6734+
6735+static void list_header(const struct ip_set *set, void *data)
6736+{
7d2f026e 6737+ const struct ip_set_nethash *map = set->data;
6738+ struct ip_set_req_nethash_create *header = data;
1aedc22c 6739+
6740+ header->hashsize = map->hashsize;
6741+ header->probes = map->probes;
6742+ header->resize = map->resize;
6743+}
6744+
6745+static int list_members_size(const struct ip_set *set)
6746+{
7d2f026e 6747+ struct ip_set_nethash *map = set->data;
1aedc22c 6748+
6749+ return (map->hashsize * sizeof(ip_set_ip_t));
6750+}
6751+
6752+static void list_members(const struct ip_set *set, void *data)
6753+{
7d2f026e 6754+ const struct ip_set_nethash *map = set->data;
1aedc22c 6755+ ip_set_ip_t i, *elem;
6756+
6757+ for (i = 0; i < map->hashsize; i++) {
6758+ elem = HARRAY_ELEM(map->members, ip_set_ip_t *, i);
6759+ ((ip_set_ip_t *)data)[i] = *elem;
6760+ }
6761+}
6762+
6763+static struct ip_set_type ip_set_nethash = {
6764+ .typename = SETTYPE_NAME,
6765+ .features = IPSET_TYPE_IP | IPSET_DATA_SINGLE,
6766+ .protocol_version = IP_SET_PROTOCOL_VERSION,
6767+ .create = &create,
6768+ .destroy = &destroy,
6769+ .flush = &flush,
6770+ .reqsize = sizeof(struct ip_set_req_nethash),
6771+ .addip = &addip,
6772+ .addip_kernel = &addip_kernel,
6773+ .retry = &retry,
6774+ .delip = &delip,
6775+ .delip_kernel = &delip_kernel,
6776+ .testip = &testip,
6777+ .testip_kernel = &testip_kernel,
6778+ .header_size = sizeof(struct ip_set_req_nethash_create),
6779+ .list_header = &list_header,
6780+ .list_members_size = &list_members_size,
6781+ .list_members = &list_members,
6782+ .me = THIS_MODULE,
6783+};
6784+
6785+MODULE_LICENSE("GPL");
6786+MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
6787+MODULE_DESCRIPTION("nethash type of IP sets");
6788+module_param(limit, int, 0600);
6789+MODULE_PARM_DESC(limit, "maximal number of elements stored in the sets");
6790+
f45e9687 6791+static int __init ip_set_nethash_init(void)
1aedc22c 6792+{
7d2f026e 6793+ init_max_page_size();
1aedc22c 6794+ return ip_set_register_set_type(&ip_set_nethash);
6795+}
6796+
f45e9687 6797+static void __exit ip_set_nethash_fini(void)
1aedc22c 6798+{
6799+ /* FIXME: possible race with ip_set_create() */
6800+ ip_set_unregister_set_type(&ip_set_nethash);
6801+}
6802+
f45e9687 6803+module_init(ip_set_nethash_init);
6804+module_exit(ip_set_nethash_fini);
7d2f026e 6805diff -uNrp --exclude=.svn a/net/ipv4/netfilter/ip_set_portmap.c linux-2.6/net/ipv4/netfilter/ip_set_portmap.c
6806--- a/net/ipv4/netfilter/ip_set_portmap.c 1970-01-01 01:00:00.000000000 +0100
6807+++ linux-2.6/net/ipv4/netfilter/ip_set_portmap.c 2008-07-08 16:52:53.965201208 +0200
6808@@ -0,0 +1,341 @@
1aedc22c 6809+/* Copyright (C) 2003-2004 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
6810+ *
6811+ * This program is free software; you can redistribute it and/or modify
6812+ * it under the terms of the GNU General Public License version 2 as
7d2f026e 6813+ * published by the Free Software Foundation.
1aedc22c 6814+ */
6815+
6816+/* Kernel module implementing a port set type as a bitmap */
6817+
6818+#include <linux/module.h>
6819+#include <linux/ip.h>
6820+#include <linux/tcp.h>
6821+#include <linux/udp.h>
6822+#include <linux/skbuff.h>
f45e9687 6823+#include <linux/version.h>
1aedc22c 6824+#include <linux/netfilter_ipv4/ip_tables.h>
6825+#include <linux/netfilter_ipv4/ip_set.h>
6826+#include <linux/errno.h>
6827+#include <asm/uaccess.h>
6828+#include <asm/bitops.h>
6829+#include <linux/spinlock.h>
6830+
6831+#include <net/ip.h>
6832+
6833+#include <linux/netfilter_ipv4/ip_set_portmap.h>
6834+
6835+/* We must handle non-linear skbs */
6836+static inline ip_set_ip_t
6837+get_port(const struct sk_buff *skb, u_int32_t flags)
6838+{
f45e9687 6839+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
5ce52adc 6840+ struct iphdr *iph = ip_hdr(skb);
f45e9687 6841+#else
6842+ struct iphdr *iph = skb->nh.iph;
6843+#endif
1aedc22c 6844+ u_int16_t offset = ntohs(iph->frag_off) & IP_OFFSET;
1aedc22c 6845+ switch (iph->protocol) {
6846+ case IPPROTO_TCP: {
6847+ struct tcphdr tcph;
6848+
6849+ /* See comments at tcp_match in ip_tables.c */
6850+ if (offset)
6851+ return INVALID_PORT;
6852+
f45e9687 6853+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
5ce52adc 6854+ if (skb_copy_bits(skb, ip_hdr(skb)->ihl*4, &tcph, sizeof(tcph)) < 0)
f45e9687 6855+#else
6856+ if (skb_copy_bits(skb, skb->nh.iph->ihl*4, &tcph, sizeof(tcph)) < 0)
6857+#endif
1aedc22c 6858+ /* No choice either */
6859+ return INVALID_PORT;
6860+
6861+ return ntohs(flags & IPSET_SRC ?
6862+ tcph.source : tcph.dest);
6863+ }
6864+ case IPPROTO_UDP: {
6865+ struct udphdr udph;
6866+
6867+ if (offset)
6868+ return INVALID_PORT;
6869+
f45e9687 6870+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
5ce52adc 6871+ if (skb_copy_bits(skb, ip_hdr(skb)->ihl*4, &udph, sizeof(udph)) < 0)
f45e9687 6872+#else
6873+ if (skb_copy_bits(skb, skb->nh.iph->ihl*4, &udph, sizeof(udph)) < 0)
6874+#endif
1aedc22c 6875+ /* No choice either */
6876+ return INVALID_PORT;
6877+
6878+ return ntohs(flags & IPSET_SRC ?
6879+ udph.source : udph.dest);
6880+ }
6881+ default:
6882+ return INVALID_PORT;
6883+ }
6884+}
6885+
6886+static inline int
6887+__testport(struct ip_set *set, ip_set_ip_t port, ip_set_ip_t *hash_port)
6888+{
7d2f026e 6889+ struct ip_set_portmap *map = set->data;
1aedc22c 6890+
6891+ if (port < map->first_port || port > map->last_port)
6892+ return -ERANGE;
6893+
6894+ *hash_port = port;
6895+ DP("set: %s, port:%u, %u", set->name, port, *hash_port);
6896+ return !!test_bit(port - map->first_port, map->members);
6897+}
6898+
6899+static int
6900+testport(struct ip_set *set, const void *data, size_t size,
6901+ ip_set_ip_t *hash_port)
6902+{
7d2f026e 6903+ const struct ip_set_req_portmap *req = data;
1aedc22c 6904+
6905+ if (size != sizeof(struct ip_set_req_portmap)) {
6906+ ip_set_printk("data length wrong (want %zu, have %zu)",
6907+ sizeof(struct ip_set_req_portmap),
6908+ size);
6909+ return -EINVAL;
6910+ }
6911+ return __testport(set, req->port, hash_port);
6912+}
6913+
6914+static int
7d2f026e 6915+testport_kernel(struct ip_set *set,
1aedc22c 6916+ const struct sk_buff *skb,
6917+ ip_set_ip_t *hash_port,
6918+ const u_int32_t *flags,
6919+ unsigned char index)
6920+{
6921+ int res;
6922+ ip_set_ip_t port = get_port(skb, flags[index]);
6923+
6924+ DP("flag %s port %u", flags[index] & IPSET_SRC ? "SRC" : "DST", port);
6925+ if (port == INVALID_PORT)
6926+ return 0;
6927+
6928+ res = __testport(set, port, hash_port);
6929+
6930+ return (res < 0 ? 0 : res);
6931+}
6932+
6933+static inline int
6934+__addport(struct ip_set *set, ip_set_ip_t port, ip_set_ip_t *hash_port)
6935+{
7d2f026e 6936+ struct ip_set_portmap *map = set->data;
1aedc22c 6937+
6938+ if (port < map->first_port || port > map->last_port)
6939+ return -ERANGE;
6940+ if (test_and_set_bit(port - map->first_port, map->members))
6941+ return -EEXIST;
6942+
6943+ *hash_port = port;
6944+ DP("port %u", port);
6945+ return 0;
6946+}
6947+
6948+static int
6949+addport(struct ip_set *set, const void *data, size_t size,
6950+ ip_set_ip_t *hash_port)
6951+{
7d2f026e 6952+ const struct ip_set_req_portmap *req = data;
1aedc22c 6953+
6954+ if (size != sizeof(struct ip_set_req_portmap)) {
6955+ ip_set_printk("data length wrong (want %zu, have %zu)",
6956+ sizeof(struct ip_set_req_portmap),
6957+ size);
6958+ return -EINVAL;
6959+ }
6960+ return __addport(set, req->port, hash_port);
6961+}
6962+
6963+static int
7d2f026e 6964+addport_kernel(struct ip_set *set,
1aedc22c 6965+ const struct sk_buff *skb,
6966+ ip_set_ip_t *hash_port,
6967+ const u_int32_t *flags,
6968+ unsigned char index)
6969+{
6970+ ip_set_ip_t port = get_port(skb, flags[index]);
6971+
6972+ if (port == INVALID_PORT)
6973+ return -EINVAL;
6974+
6975+ return __addport(set, port, hash_port);
6976+}
6977+
6978+static inline int
6979+__delport(struct ip_set *set, ip_set_ip_t port, ip_set_ip_t *hash_port)
6980+{
7d2f026e 6981+ struct ip_set_portmap *map = set->data;
1aedc22c 6982+
6983+ if (port < map->first_port || port > map->last_port)
6984+ return -ERANGE;
6985+ if (!test_and_clear_bit(port - map->first_port, map->members))
6986+ return -EEXIST;
6987+
6988+ *hash_port = port;
6989+ DP("port %u", port);
6990+ return 0;
6991+}
6992+
6993+static int
6994+delport(struct ip_set *set, const void *data, size_t size,
6995+ ip_set_ip_t *hash_port)
6996+{
7d2f026e 6997+ const struct ip_set_req_portmap *req = data;
1aedc22c 6998+
6999+ if (size != sizeof(struct ip_set_req_portmap)) {
7000+ ip_set_printk("data length wrong (want %zu, have %zu)",
7001+ sizeof(struct ip_set_req_portmap),
7002+ size);
7003+ return -EINVAL;
7004+ }
7005+ return __delport(set, req->port, hash_port);
7006+}
7007+
7008+static int
7d2f026e 7009+delport_kernel(struct ip_set *set,
1aedc22c 7010+ const struct sk_buff *skb,
7011+ ip_set_ip_t *hash_port,
7012+ const u_int32_t *flags,
7013+ unsigned char index)
7014+{
7015+ ip_set_ip_t port = get_port(skb, flags[index]);
7016+
7017+ if (port == INVALID_PORT)
7018+ return -EINVAL;
7019+
7020+ return __delport(set, port, hash_port);
7021+}
7022+
7023+static int create(struct ip_set *set, const void *data, size_t size)
7024+{
7025+ int newbytes;
7d2f026e 7026+ const struct ip_set_req_portmap_create *req = data;
1aedc22c 7027+ struct ip_set_portmap *map;
7028+
7029+ if (size != sizeof(struct ip_set_req_portmap_create)) {
7030+ ip_set_printk("data length wrong (want %zu, have %zu)",
7031+ sizeof(struct ip_set_req_portmap_create),
7032+ size);
7033+ return -EINVAL;
7034+ }
7035+
7036+ DP("from %u to %u", req->from, req->to);
7037+
7038+ if (req->from > req->to) {
7039+ DP("bad port range");
7040+ return -ENOEXEC;
7041+ }
7042+
7043+ if (req->to - req->from > MAX_RANGE) {
7044+ ip_set_printk("range too big (max %d ports)",
7045+ MAX_RANGE+1);
7046+ return -ENOEXEC;
7047+ }
7048+
7049+ map = kmalloc(sizeof(struct ip_set_portmap), GFP_KERNEL);
7050+ if (!map) {
7051+ DP("out of memory for %d bytes",
7052+ sizeof(struct ip_set_portmap));
7053+ return -ENOMEM;
7054+ }
7055+ map->first_port = req->from;
7056+ map->last_port = req->to;
7057+ newbytes = bitmap_bytes(req->from, req->to);
7058+ map->members = kmalloc(newbytes, GFP_KERNEL);
7059+ if (!map->members) {
7060+ DP("out of memory for %d bytes", newbytes);
7061+ kfree(map);
7062+ return -ENOMEM;
7063+ }
7064+ memset(map->members, 0, newbytes);
7065+
7066+ set->data = map;
7067+ return 0;
7068+}
7069+
7070+static void destroy(struct ip_set *set)
7071+{
7d2f026e 7072+ struct ip_set_portmap *map = set->data;
1aedc22c 7073+
7074+ kfree(map->members);
7075+ kfree(map);
7076+
7077+ set->data = NULL;
7078+}
7079+
7080+static void flush(struct ip_set *set)
7081+{
7d2f026e 7082+ struct ip_set_portmap *map = set->data;
1aedc22c 7083+ memset(map->members, 0, bitmap_bytes(map->first_port, map->last_port));
7084+}
7085+
7086+static void list_header(const struct ip_set *set, void *data)
7087+{
7d2f026e 7088+ const struct ip_set_portmap *map = set->data;
7089+ struct ip_set_req_portmap_create *header = data;
1aedc22c 7090+
7091+ DP("list_header %u %u", map->first_port, map->last_port);
7092+
7093+ header->from = map->first_port;
7094+ header->to = map->last_port;
7095+}
7096+
7097+static int list_members_size(const struct ip_set *set)
7098+{
7d2f026e 7099+ const struct ip_set_portmap *map = set->data;
1aedc22c 7100+
7101+ return bitmap_bytes(map->first_port, map->last_port);
7102+}
7103+
7104+static void list_members(const struct ip_set *set, void *data)
7105+{
7d2f026e 7106+ const struct ip_set_portmap *map = set->data;
1aedc22c 7107+ int bytes = bitmap_bytes(map->first_port, map->last_port);
7108+
7109+ memcpy(data, map->members, bytes);
7110+}
7111+
7112+static struct ip_set_type ip_set_portmap = {
7113+ .typename = SETTYPE_NAME,
7114+ .features = IPSET_TYPE_PORT | IPSET_DATA_SINGLE,
7115+ .protocol_version = IP_SET_PROTOCOL_VERSION,
7116+ .create = &create,
7117+ .destroy = &destroy,
7118+ .flush = &flush,
7119+ .reqsize = sizeof(struct ip_set_req_portmap),
7120+ .addip = &addport,
7121+ .addip_kernel = &addport_kernel,
7122+ .delip = &delport,
7123+ .delip_kernel = &delport_kernel,
7124+ .testip = &testport,
7125+ .testip_kernel = &testport_kernel,
7126+ .header_size = sizeof(struct ip_set_req_portmap_create),
7127+ .list_header = &list_header,
7128+ .list_members_size = &list_members_size,
7129+ .list_members = &list_members,
7130+ .me = THIS_MODULE,
7131+};
7132+
7133+MODULE_LICENSE("GPL");
7134+MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
7135+MODULE_DESCRIPTION("portmap type of IP sets");
7136+
f45e9687 7137+static int __init ip_set_portmap_init(void)
1aedc22c 7138+{
7139+ return ip_set_register_set_type(&ip_set_portmap);
7140+}
7141+
f45e9687 7142+static void __exit ip_set_portmap_fini(void)
1aedc22c 7143+{
7144+ /* FIXME: possible race with ip_set_create() */
7145+ ip_set_unregister_set_type(&ip_set_portmap);
7146+}
7147+
f45e9687 7148+module_init(ip_set_portmap_init);
7149+module_exit(ip_set_portmap_fini);
7d2f026e 7150diff -uNrp --exclude=.svn a/net/ipv4/netfilter/ipt_set.c linux-2.6/net/ipv4/netfilter/ipt_set.c
7151--- a/net/ipv4/netfilter/ipt_set.c 1970-01-01 01:00:00.000000000 +0100
7152+++ linux-2.6/net/ipv4/netfilter/ipt_set.c 2008-07-08 16:52:53.965201208 +0200
7153@@ -0,0 +1,159 @@
1aedc22c 7154+/* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu>
7155+ * Patrick Schaaf <bof@bof.de>
7156+ * Martin Josefsson <gandalf@wlug.westbo.se>
7157+ * Copyright (C) 2003-2004 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
7158+ *
7159+ * This program is free software; you can redistribute it and/or modify
7160+ * it under the terms of the GNU General Public License version 2 as
7d2f026e 7161+ * published by the Free Software Foundation.
1aedc22c 7162+ */
7163+
9f54053a 7164+/* Kernel module to match an IP set. */
1aedc22c 7165+
1aedc22c 7166+#include <linux/module.h>
9f54053a
JR
7167+#include <linux/ip.h>
7168+#include <linux/skbuff.h>
1aedc22c 7169+#include <linux/version.h>
9f54053a
JR
7170+
7171+#include <linux/netfilter_ipv4/ip_tables.h>
7172+#include <linux/netfilter_ipv4/ip_set.h>
1aedc22c 7173+#include <linux/netfilter_ipv4/ipt_set.h>
7174+
9f54053a
JR
7175+static inline int
7176+match_set(const struct ipt_set_info *info,
7177+ const struct sk_buff *skb,
7178+ int inv)
7179+{
7180+ if (ip_set_testip_kernel(info->index, skb, info->flags))
7181+ inv = !inv;
7182+ return inv;
7183+}
7184+
f45e9687 7185+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,23)
7186+static bool
7187+#else
9f54053a 7188+static int
f45e9687 7189+#endif
9f54053a
JR
7190+match(const struct sk_buff *skb,
7191+ const struct net_device *in,
7192+ const struct net_device *out,
1aedc22c 7193+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,17)
9f54053a 7194+ const struct xt_match *match,
1aedc22c 7195+#endif
9f54053a 7196+ const void *matchinfo,
f45e9687 7197+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,23)
7198+ int offset, unsigned int protoff, bool *hotdrop)
7199+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16)
9f54053a 7200+ int offset, unsigned int protoff, int *hotdrop)
1aedc22c 7201+#else
9f54053a 7202+ int offset, int *hotdrop)
1aedc22c 7203+#endif
7204+{
9f54053a
JR
7205+ const struct ipt_set_info_match *info = matchinfo;
7206+
7207+ return match_set(&info->match_set,
7208+ skb,
7209+ info->match_set.flags[0] & IPSET_MATCH_INV);
1aedc22c 7210+}
7211+
f45e9687 7212+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,23)
7d2f026e 7213+static bool
f45e9687 7214+#else
1aedc22c 7215+static int
f45e9687 7216+#endif
1aedc22c 7217+checkentry(const char *tablename,
7218+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16)
9f54053a 7219+ const void *inf,
1aedc22c 7220+#else
9f54053a 7221+ const struct ipt_ip *ip,
1aedc22c 7222+#endif
7223+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,17)
9f54053a 7224+ const struct xt_match *match,
1aedc22c 7225+#endif
9f54053a 7226+ void *matchinfo,
1aedc22c 7227+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
9f54053a 7228+ unsigned int matchsize,
1aedc22c 7229+#endif
7230+ unsigned int hook_mask)
7231+{
7d2f026e 7232+ struct ipt_set_info_match *info = matchinfo;
1aedc22c 7233+ ip_set_id_t index;
7234+
7235+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
9f54053a
JR
7236+ if (matchsize != IPT_ALIGN(sizeof(struct ipt_set_info_match))) {
7237+ ip_set_printk("invalid matchsize %d", matchsize);
1aedc22c 7238+ return 0;
7239+ }
7240+#endif
7241+
9f54053a
JR
7242+ index = ip_set_get_byindex(info->match_set.index);
7243+
7244+ if (index == IP_SET_INVALID_ID) {
7245+ ip_set_printk("Cannot find set indentified by id %u to match",
7246+ info->match_set.index);
7247+ return 0; /* error */
1aedc22c 7248+ }
9f54053a 7249+ if (info->match_set.flags[IP_SET_MAX_BINDINGS] != 0) {
1aedc22c 7250+ ip_set_printk("That's nasty!");
7251+ return 0; /* error */
7252+ }
7253+
7254+ return 1;
7255+}
7256+
7257+static void destroy(
7258+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,17)
9f54053a 7259+ const struct xt_match *match,
1aedc22c 7260+#endif
7261+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
9f54053a 7262+ void *matchinfo, unsigned int matchsize)
1aedc22c 7263+#else
9f54053a 7264+ void *matchinfo)
1aedc22c 7265+#endif
7266+{
9f54053a 7267+ struct ipt_set_info_match *info = matchinfo;
1aedc22c 7268+
7269+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
9f54053a
JR
7270+ if (matchsize != IPT_ALIGN(sizeof(struct ipt_set_info_match))) {
7271+ ip_set_printk("invalid matchsize %d", matchsize);
1aedc22c 7272+ return;
7273+ }
7274+#endif
9f54053a 7275+ ip_set_put(info->match_set.index);
1aedc22c 7276+}
7277+
9f54053a
JR
7278+static struct ipt_match set_match = {
7279+ .name = "set",
7280+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21)
7281+ .family = AF_INET,
7282+#endif
7283+ .match = &match,
1aedc22c 7284+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,17)
9f54053a 7285+ .matchsize = sizeof(struct ipt_set_info_match),
1aedc22c 7286+#endif
9f54053a
JR
7287+ .checkentry = &checkentry,
7288+ .destroy = &destroy,
7289+ .me = THIS_MODULE
1aedc22c 7290+};
7291+
7292+MODULE_LICENSE("GPL");
7293+MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
9f54053a 7294+MODULE_DESCRIPTION("iptables IP set match module");
1aedc22c 7295+
9f54053a
JR
7296+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21)
7297+#define ipt_register_match xt_register_match
7298+#define ipt_unregister_match xt_unregister_match
7299+#endif
7300+
7301+static int __init ipt_ipset_init(void)
1aedc22c 7302+{
9f54053a 7303+ return ipt_register_match(&set_match);
1aedc22c 7304+}
7305+
9f54053a 7306+static void __exit ipt_ipset_fini(void)
1aedc22c 7307+{
9f54053a 7308+ ipt_unregister_match(&set_match);
1aedc22c 7309+}
7310+
9f54053a
JR
7311+module_init(ipt_ipset_init);
7312+module_exit(ipt_ipset_fini);
7d2f026e 7313diff -uNrp --exclude=.svn a/net/ipv4/netfilter/ipt_SET.c linux-2.6/net/ipv4/netfilter/ipt_SET.c
7314--- a/net/ipv4/netfilter/ipt_SET.c 1970-01-01 01:00:00.000000000 +0100
7315+++ linux-2.6/net/ipv4/netfilter/ipt_SET.c 2008-07-08 16:52:53.965201208 +0200
7316@@ -0,0 +1,179 @@
1aedc22c 7317+/* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu>
7318+ * Patrick Schaaf <bof@bof.de>
7319+ * Martin Josefsson <gandalf@wlug.westbo.se>
7320+ * Copyright (C) 2003-2004 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
7321+ *
7322+ * This program is free software; you can redistribute it and/or modify
7323+ * it under the terms of the GNU General Public License version 2 as
7d2f026e 7324+ * published by the Free Software Foundation.
1aedc22c 7325+ */
7326+
9f54053a 7327+/* ipt_SET.c - netfilter target to manipulate IP sets */
1aedc22c 7328+
9f54053a 7329+#include <linux/types.h>
1aedc22c 7330+#include <linux/ip.h>
9f54053a
JR
7331+#include <linux/timer.h>
7332+#include <linux/module.h>
7333+#include <linux/netfilter.h>
7334+#include <linux/netdevice.h>
7335+#include <linux/if.h>
7336+#include <linux/inetdevice.h>
1aedc22c 7337+#include <linux/version.h>
9f54053a
JR
7338+#include <net/protocol.h>
7339+#include <net/checksum.h>
7340+#include <linux/netfilter_ipv4.h>
f45e9687 7341+#include <linux/netfilter_ipv4/ip_tables.h>
1aedc22c 7342+#include <linux/netfilter_ipv4/ipt_set.h>
7343+
9f54053a 7344+static unsigned int
7d2f026e 7345+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
7346+target(struct sk_buff *skb,
7347+#else
9f54053a 7348+target(struct sk_buff **pskb,
7d2f026e 7349+#endif
9f54053a
JR
7350+ const struct net_device *in,
7351+ const struct net_device *out,
7352+ unsigned int hooknum,
1aedc22c 7353+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,17)
9f54053a 7354+ const struct xt_target *target,
1aedc22c 7355+#endif
9f54053a
JR
7356+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
7357+ const void *targinfo,
7358+ void *userinfo)
1aedc22c 7359+#else
9f54053a 7360+ const void *targinfo)
1aedc22c 7361+#endif
7362+{
9f54053a 7363+ const struct ipt_set_info_target *info = targinfo;
7d2f026e 7364+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
7365+ struct sk_buff *skb = *pskb;
7366+#endif
7367+
9f54053a
JR
7368+
7369+ if (info->add_set.index != IP_SET_INVALID_ID)
7370+ ip_set_addip_kernel(info->add_set.index,
7d2f026e 7371+ skb,
9f54053a
JR
7372+ info->add_set.flags);
7373+ if (info->del_set.index != IP_SET_INVALID_ID)
7374+ ip_set_delip_kernel(info->del_set.index,
7d2f026e 7375+ skb,
9f54053a
JR
7376+ info->del_set.flags);
7377+
7378+ return IPT_CONTINUE;
1aedc22c 7379+}
7380+
f45e9687 7381+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,23)
7382+static bool
7383+#else
1aedc22c 7384+static int
f45e9687 7385+#endif
1aedc22c 7386+checkentry(const char *tablename,
7387+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16)
9f54053a 7388+ const void *e,
1aedc22c 7389+#else
9f54053a 7390+ const struct ipt_entry *e,
1aedc22c 7391+#endif
7392+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,17)
9f54053a 7393+ const struct xt_target *target,
1aedc22c 7394+#endif
9f54053a 7395+ void *targinfo,
1aedc22c 7396+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
7d2f026e 7397+ unsigned int targinfosize,
1aedc22c 7398+#endif
7399+ unsigned int hook_mask)
7400+{
7d2f026e 7401+ struct ipt_set_info_target *info = targinfo;
1aedc22c 7402+ ip_set_id_t index;
7403+
7404+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
9f54053a
JR
7405+ if (targinfosize != IPT_ALIGN(sizeof(*info))) {
7406+ DP("bad target info size %u", targinfosize);
1aedc22c 7407+ return 0;
7408+ }
7409+#endif
7410+
9f54053a
JR
7411+ if (info->add_set.index != IP_SET_INVALID_ID) {
7412+ index = ip_set_get_byindex(info->add_set.index);
7413+ if (index == IP_SET_INVALID_ID) {
7414+ ip_set_printk("cannot find add_set index %u as target",
7415+ info->add_set.index);
7416+ return 0; /* error */
7417+ }
1aedc22c 7418+ }
9f54053a
JR
7419+
7420+ if (info->del_set.index != IP_SET_INVALID_ID) {
7421+ index = ip_set_get_byindex(info->del_set.index);
7422+ if (index == IP_SET_INVALID_ID) {
7423+ ip_set_printk("cannot find del_set index %u as target",
7424+ info->del_set.index);
7425+ return 0; /* error */
7426+ }
7427+ }
7428+ if (info->add_set.flags[IP_SET_MAX_BINDINGS] != 0
7429+ || info->del_set.flags[IP_SET_MAX_BINDINGS] != 0) {
1aedc22c 7430+ ip_set_printk("That's nasty!");
7431+ return 0; /* error */
7432+ }
7433+
7434+ return 1;
7435+}
7436+
7437+static void destroy(
7438+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,17)
9f54053a 7439+ const struct xt_target *target,
1aedc22c 7440+#endif
7441+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
9f54053a 7442+ void *targetinfo, unsigned int targetsize)
1aedc22c 7443+#else
9f54053a 7444+ void *targetinfo)
1aedc22c 7445+#endif
7446+{
9f54053a 7447+ struct ipt_set_info_target *info = targetinfo;
1aedc22c 7448+
7449+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
9f54053a
JR
7450+ if (targetsize != IPT_ALIGN(sizeof(struct ipt_set_info_target))) {
7451+ ip_set_printk("invalid targetsize %d", targetsize);
1aedc22c 7452+ return;
7453+ }
7454+#endif
9f54053a
JR
7455+ if (info->add_set.index != IP_SET_INVALID_ID)
7456+ ip_set_put(info->add_set.index);
7457+ if (info->del_set.index != IP_SET_INVALID_ID)
7458+ ip_set_put(info->del_set.index);
1aedc22c 7459+}
7460+
9f54053a
JR
7461+static struct ipt_target SET_target = {
7462+ .name = "SET",
7463+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21)
7464+ .family = AF_INET,
7465+#endif
7466+ .target = target,
1aedc22c 7467+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,17)
9f54053a 7468+ .targetsize = sizeof(struct ipt_set_info_target),
1aedc22c 7469+#endif
9f54053a
JR
7470+ .checkentry = checkentry,
7471+ .destroy = destroy,
7472+ .me = THIS_MODULE
1aedc22c 7473+};
7474+
7475+MODULE_LICENSE("GPL");
7476+MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
9f54053a 7477+MODULE_DESCRIPTION("iptables IP set target module");
1aedc22c 7478+
9f54053a
JR
7479+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21)
7480+#define ipt_register_target xt_register_target
7481+#define ipt_unregister_target xt_unregister_target
7482+#endif
7483+
7484+static int __init ipt_SET_init(void)
1aedc22c 7485+{
9f54053a 7486+ return ipt_register_target(&SET_target);
1aedc22c 7487+}
7488+
9f54053a 7489+static void __exit ipt_SET_fini(void)
1aedc22c 7490+{
9f54053a 7491+ ipt_unregister_target(&SET_target);
1aedc22c 7492+}
7493+
9f54053a
JR
7494+module_init(ipt_SET_init);
7495+module_exit(ipt_SET_fini);
7d2f026e 7496diff -uNrp --exclude=.svn a/net/ipv4/netfilter/Kconfig.ladd linux-2.6/net/ipv4/netfilter/Kconfig.ladd
7497--- a/net/ipv4/netfilter/Kconfig.ladd 1970-01-01 01:00:00.000000000 +0100
7498+++ linux-2.6/net/ipv4/netfilter/Kconfig.ladd 2008-07-08 16:52:53.965201208 +0200
f45e9687 7499@@ -0,0 +1,116 @@
9f54053a
JR
7500+config IP_NF_SET
7501+ tristate "IP set support"
7502+ depends on INET && NETFILTER
7503+ help
7504+ This option adds IP set support to the kernel.
7505+ In order to define and use sets, you need the userspace utility
7506+ ipset(8).
7507+
7508+ To compile it as a module, choose M here. If unsure, say N.
7509+
7510+config IP_NF_SET_MAX
7511+ int "Maximum number of IP sets"
7512+ default 256
7513+ range 2 65534
7514+ depends on IP_NF_SET
7515+ help
7516+ You can define here default value of the maximum number
7517+ of IP sets for the kernel.
7518+
7519+ The value can be overriden by the 'max_sets' module
7520+ parameter of the 'ip_set' module.
7521+
7522+config IP_NF_SET_HASHSIZE
7523+ int "Hash size for bindings of IP sets"
7524+ default 1024
7525+ depends on IP_NF_SET
7526+ help
7527+ You can define here default value of the hash size for
7528+ bindings of IP sets.
7529+
7530+ The value can be overriden by the 'hash_size' module
7531+ parameter of the 'ip_set' module.
7532+
7533+config IP_NF_SET_IPMAP
7534+ tristate "ipmap set support"
7535+ depends on IP_NF_SET
7536+ help
7537+ This option adds the ipmap set type support.
7538+
7539+ To compile it as a module, choose M here. If unsure, say N.
7540+
7541+config IP_NF_SET_MACIPMAP
7542+ tristate "macipmap set support"
7543+ depends on IP_NF_SET
7544+ help
7545+ This option adds the macipmap set type support.
7546+
7547+ To compile it as a module, choose M here. If unsure, say N.
7548+
7549+config IP_NF_SET_PORTMAP
7550+ tristate "portmap set support"
7551+ depends on IP_NF_SET
7552+ help
7553+ This option adds the portmap set type support.
7554+
7555+ To compile it as a module, choose M here. If unsure, say N.
7556+
7557+config IP_NF_SET_IPHASH
7558+ tristate "iphash set support"
7559+ depends on IP_NF_SET
7560+ help
7561+ This option adds the iphash set type support.
7562+
7563+ To compile it as a module, choose M here. If unsure, say N.
7564+
7565+config IP_NF_SET_NETHASH
7566+ tristate "nethash set support"
7567+ depends on IP_NF_SET
7568+ help
7569+ This option adds the nethash set type support.
7570+
7571+ To compile it as a module, choose M here. If unsure, say N.
7572+
7573+config IP_NF_SET_IPPORTHASH
7574+ tristate "ipporthash set support"
7575+ depends on IP_NF_SET
7576+ help
7577+ This option adds the ipporthash set type support.
7578+
7579+ To compile it as a module, choose M here. If unsure, say N.
7580+
7581+config IP_NF_SET_IPTREE
7582+ tristate "iptree set support"
7583+ depends on IP_NF_SET
7584+ help
7585+ This option adds the iptree set type support.
7586+
7587+ To compile it as a module, choose M here. If unsure, say N.
7588+
f45e9687 7589+config IP_NF_SET_IPTREEMAP
7590+ tristate "iptreemap set support"
7591+ depends on IP_NF_SET
7592+ help
7593+ This option adds the iptreemap set type support.
7594+
7595+ To compile it as a module, choose M here. If unsure, say N.
7596+
9f54053a
JR
7597+config IP_NF_MATCH_SET
7598+ tristate "set match support"
7599+ depends on IP_NF_SET
7600+ help
7601+ Set matching matches against given IP sets.
7602+ You need the ipset utility to create and set up the sets.
7603+
7604+ To compile it as a module, choose M here. If unsure, say N.
7605+
7606+config IP_NF_TARGET_SET
7607+ tristate "SET target support"
7608+ depends on IP_NF_SET
7609+ help
7610+ The SET target makes possible to add/delete entries
7611+ in IP sets.
7612+ You need the ipset utility to create and set up the sets.
7613+
7614+ To compile it as a module, choose M here. If unsure, say N.
7615+
7d2f026e 7616diff -uNrp --exclude=.svn a/net/ipv4/netfilter/Makefile.ladd linux-2.6/net/ipv4/netfilter/Makefile.ladd
7617--- a/net/ipv4/netfilter/Makefile.ladd 1970-01-01 01:00:00.000000000 +0100
7618+++ linux-2.6/net/ipv4/netfilter/Makefile.ladd 2008-07-08 16:52:53.965201208 +0200
f45e9687 7619@@ -0,0 +1,2 @@
7620+obj-$(CONFIG_IP_NF_MATCH_TTL) += ipt_ttl.o
9f54053a 7621+obj-$(CONFIG_IP_NF_MATCH_SET) += ipt_set.o
7d2f026e 7622diff -uNrp --exclude=.svn a/net/ipv4/netfilter/Makefile.ladd_2 linux-2.6/net/ipv4/netfilter/Makefile.ladd_2
7623--- a/net/ipv4/netfilter/Makefile.ladd_2 1970-01-01 01:00:00.000000000 +0100
7624+++ linux-2.6/net/ipv4/netfilter/Makefile.ladd_2 2008-07-08 16:52:53.965201208 +0200
f45e9687 7625@@ -0,0 +1,13 @@
7626+obj-$(CONFIG_IP_NF_TARGET_TTL) += ipt_TTL.o
9f54053a
JR
7627+obj-$(CONFIG_IP_NF_TARGET_SET) += ipt_SET.o
7628+
7629+# sets
7630+obj-$(CONFIG_IP_NF_SET) += ip_set.o
7631+obj-$(CONFIG_IP_NF_SET_IPMAP) += ip_set_ipmap.o
7632+obj-$(CONFIG_IP_NF_SET_PORTMAP) += ip_set_portmap.o
7633+obj-$(CONFIG_IP_NF_SET_MACIPMAP) += ip_set_macipmap.o
7634+obj-$(CONFIG_IP_NF_SET_IPHASH) += ip_set_iphash.o
7635+obj-$(CONFIG_IP_NF_SET_NETHASH) += ip_set_nethash.o
7636+obj-$(CONFIG_IP_NF_SET_IPPORTHASH) += ip_set_ipporthash.o
7637+obj-$(CONFIG_IP_NF_SET_IPTREE) += ip_set_iptree.o
f45e9687 7638+obj-$(CONFIG_IP_NF_SET_IPTREEMAP) += ip_set_iptreemap.o
This page took 1.339827 seconds and 4 git commands to generate.