+--- a/include/linux/netfilter_ipv4/Kbuild
++++ b/include/linux/netfilter_ipv4/Kbuild
+@@ -45,3 +45,14 @@
+
+ unifdef-y += ip_queue.h
+ unifdef-y += ip_tables.h
++
++unifdef-y += ip_set.h
++header-y += ip_set_iphash.h
++header-y += ip_set_ipmap.h
++header-y += ip_set_ipporthash.h
++unifdef-y += ip_set_iptree.h
++unifdef-y += ip_set_iptreemap.h
++header-y += ip_set_jhash.h
++header-y += ip_set_macipmap.h
++unifdef-y += ip_set_nethash.h
++header-y += ip_set_portmap.h
--- /dev/null
+++ b/include/linux/netfilter_ipv4/ip_set.h
@@ -0,0 +1,498 @@
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
-+ * published by the Free Software Foundation.
++ * published by the Free Software Foundation.
+ */
+
+#if 0
+ * - in order to "deal with" backward compatibility, renamed to ipset
+ */
+
-+/*
-+ * Used so that the kernel module and ipset-binary can match their versions
++/*
++ * Used so that the kernel module and ipset-binary can match their versions
+ */
+#define IP_SET_PROTOCOL_VERSION 2
+
+ *
+ * The representation works in HOST byte order, because most set types
+ * will perform arithmetic operations and compare operations.
-+ *
++ *
+ * For now the type is an uint32_t.
+ *
+ * Make sure to ONLY use the functions when translating and parsing
+ * 200-299: list, save, restore
+ */
+
-+/* Single shot operations:
-+ * version, create, destroy, flush, rename and swap
++/* Single shot operations:
++ * version, create, destroy, flush, rename and swap
+ *
+ * Sets are identified by name.
+ */
+ unsigned version;
+};
+
-+/* Double shots operations:
++/* Double shots operations:
+ * add, del, test, bind and unbind.
+ *
+ * First we query the kernel to get the index and type of the target set,
+};
+
+#define IP_SET_OP_UNBIND_SET 0x00000105 /* Unbind an IP from a set */
-+/* Uses ip_set_req_bind, with type speficic addage
++/* Uses ip_set_req_bind, with type speficic addage
+ * index = 0 means unbinding for all sets */
+
+#define IP_SET_OP_TEST_BIND_SET 0x00000106 /* Test binding an IP to a set */
+#define IP_SET_OP_LIST 0x00000203
+struct ip_set_req_list {
+ IP_SET_REQ_BYINDEX;
-+ /* sets number of struct ip_set_list in reply */
++ /* sets number of struct ip_set_list in reply */
+};
+
+struct ip_set_list {
+/* The restore operation */
+#define IP_SET_OP_RESTORE 0x00000205
+/* Uses ip_set_req_setnames followed by ip_set_restore structures
-+ * plus a marker ip_set_restore, followed by ip_set_hash_save
++ * plus a marker ip_set_restore, followed by ip_set_hash_save
+ * structures.
+ */
+struct ip_set_restore {
+ * return 0 if not in set, 1 if in set.
+ */
+ int (*testip_kernel) (struct ip_set *set,
-+ const struct sk_buff * skb,
++ const struct sk_buff * skb,
+ ip_set_ip_t *ip,
+ const u_int32_t *flags,
+ unsigned char index);
+ * and -ERANGE if the address lies outside the set bounds.
+ * If the address was not already in the set, 0 is returned.
+ */
-+ int (*addip) (struct ip_set *set,
++ int (*addip) (struct ip_set *set,
+ const void *data, size_t size,
+ ip_set_ip_t *ip);
+
+ * If the address was not already in the set, 0 is returned.
+ */
+ int (*addip_kernel) (struct ip_set *set,
-+ const struct sk_buff * skb,
++ const struct sk_buff * skb,
+ ip_set_ip_t *ip,
+ const u_int32_t *flags,
+ unsigned char index);
+ * and -ERANGE if the address lies outside the set bounds.
+ * If the address really was in the set, 0 is returned.
+ */
-+ int (*delip) (struct ip_set *set,
++ int (*delip) (struct ip_set *set,
+ const void *data, size_t size,
+ ip_set_ip_t *ip);
+
+ * If the address really was in the set, 0 is returned.
+ */
+ int (*delip_kernel) (struct ip_set *set,
-+ const struct sk_buff * skb,
++ const struct sk_buff * skb,
+ ip_set_ip_t *ip,
+ const u_int32_t *flags,
+ unsigned char index);
+ /* Listing: Get the header
+ *
+ * Fill in the information in "data".
-+ * This function is always run after list_header_size() under a
-+ * writelock on the set. Therefor is the length of "data" always
-+ * correct.
++ * This function is always run after list_header_size() under a
++ * writelock on the set. Therefor is the length of "data" always
++ * correct.
+ */
-+ void (*list_header) (const struct ip_set *set,
++ void (*list_header) (const struct ip_set *set,
+ void *data);
+
+ /* Listing: Get the size for the set members
+ /* Listing: Get the set members
+ *
+ * Fill in the information in "data".
-+ * This function is always run after list_member_size() under a
-+ * writelock on the set. Therefor is the length of "data" always
-+ * correct.
++ * This function is always run after list_member_size() under a
++ * writelock on the set. Therefor is the length of "data" always
++ * correct.
+ */
+ void (*list_members) (const struct ip_set *set,
+ void *data);
+{
+ unsigned int bits = 32;
+ ip_set_ip_t maskaddr;
-+
++
+ if (mask == 0xFFFFFFFF)
+ return bits;
-+
++
+ maskaddr = 0xFFFFFFFE;
+ while (--bits >= 0 && maskaddr != mask)
+ maskaddr <<= 1;
-+
++
+ return bits;
+}
+
+range_to_mask(ip_set_ip_t from, ip_set_ip_t to, unsigned int *bits)
+{
+ ip_set_ip_t mask = 0xFFFFFFFE;
-+
++
+ *bits = 32;
+ while (--(*bits) >= 0 && mask && (to & mask) != from)
+ mask <<= 1;
-+
++
+ return mask;
+}
-+
++
+#endif /* __IP_SET_IPMAP_H */
--- /dev/null
+++ b/include/linux/netfilter_ipv4/ip_set_ipporthash.h
+ void *arrays[0];
+};
+
-+static inline void *
++static inline void *
+harray_malloc(size_t hashsize, size_t typesize, int flags)
+{
+ struct harray *harray;
+ size = hashsize/max_elements;
+ if (hashsize % max_elements)
+ size++;
-+
++
+ /* Last pointer signals end of arrays */
+ harray = kmalloc(sizeof(struct harray) + (size + 1) * sizeof(void *),
+ flags);
+
+ if (!harray)
+ return NULL;
-+
++
+ for (i = 0; i < size - 1; i++) {
+ harray->arrays[i] = kmalloc(max_elements * typesize, flags);
+ if (!harray->arrays[i])
+ goto undo;
+ memset(harray->arrays[i], 0, max_elements * typesize);
+ }
-+ harray->arrays[i] = kmalloc((hashsize - i * max_elements) * typesize,
++ harray->arrays[i] = kmalloc((hashsize - i * max_elements) * typesize,
+ flags);
+ if (!harray->arrays[i])
+ goto undo;
+
+ harray->max_elements = max_elements;
+ harray->arrays[size] = NULL;
-+
++
+ return (void *)harray;
+
+ undo:
+{
+ struct harray *harray = (struct harray *) h;
+ size_t i;
-+
++
+ for (i = 0; harray->arrays[i] != NULL; i++)
+ kfree(harray->arrays[i]);
+ kfree(harray);
+{
+ struct harray *harray = (struct harray *) h;
+ size_t i;
-+
++
+ for (i = 0; harray->arrays[i+1] != NULL; i++)
+ memset(harray->arrays[i], 0, harray->max_elements * typesize);
-+ memset(harray->arrays[i], 0,
++ memset(harray->arrays[i], 0,
+ (hashsize - i * harray->max_elements) * typesize);
+}
+
+
+static unsigned char shifts[] = {255, 253, 249, 241, 225, 193, 129, 1};
+
-+static inline ip_set_ip_t
++static inline ip_set_ip_t
+pack(ip_set_ip_t ip, unsigned char cidr)
+{
+ ip_set_ip_t addr, *paddr = &addr;
+ DP("ip:%u.%u.%u.%u/%u", NIPQUAD(addr), cidr);
+#endif
+ n = cidr / 8;
-+ t = cidr % 8;
++ t = cidr % 8;
+ a = &((unsigned char *)paddr)[n];
+ *a = *a /(1 << (8 - t)) + shifts[t];
+#ifdef __KERNEL__
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
-+ * published by the Free Software Foundation.
++ * published by the Free Software Foundation.
+ */
+
+/* Kernel module for IP set management */
+
+/*
+ * Sets are identified either by the index in ip_set_list or by id.
-+ * The id never changes and is used to find a key in the hash.
-+ * The index may change by swapping and used at all other places
++ * The id never changes and is used to find a key in the hash.
++ * The index may change by swapping and used at all other places
+ * (set/SET netfilter modules, binding value, etc.)
+ *
+ * Userspace requests are serialized by ip_set_mutex and sets can
-+ * be deleted only from userspace. Therefore ip_set_list locking
++ * be deleted only from userspace. Therefore ip_set_list locking
+ * must obey the following rules:
+ *
+ * - kernel requests: read and write locking mandatory
+ list_for_each_entry(set_hash, &ip_set_hash[key], list)
+ if (set_hash->id == id && set_hash->ip == ip)
+ return set_hash;
-+
++
+ return NULL;
+}
+
+static ip_set_id_t
+ip_set_find_in_hash(ip_set_id_t id, ip_set_ip_t ip)
+{
-+ u_int32_t key = jhash_2words(id, ip, ip_set_hash_random)
++ u_int32_t key = jhash_2words(id, ip, ip_set_hash_random)
+ % ip_set_bindings_hash_size;
+ struct ip_set_hash *set_hash;
+
+ ASSERT_READ_LOCK(&ip_set_lock);
+ IP_SET_ASSERT(ip_set_list[id]);
-+ DP("set: %s, ip: %u.%u.%u.%u", ip_set_list[id]->name, HIPQUAD(ip));
-+
++ DP("set: %s, ip: %u.%u.%u.%u", ip_set_list[id]->name, HIPQUAD(ip));
++
+ set_hash = __ip_set_find(key, id, ip);
-+
-+ DP("set: %s, ip: %u.%u.%u.%u, binding: %s", ip_set_list[id]->name,
++
++ DP("set: %s, ip: %u.%u.%u.%u, binding: %s", ip_set_list[id]->name,
+ HIPQUAD(ip),
+ set_hash != NULL ? ip_set_list[set_hash->binding]->name : "");
+
+ return (set_hash != NULL ? set_hash->binding : IP_SET_INVALID_ID);
+}
+
-+static inline void
++static inline void
+__set_hash_del(struct ip_set_hash *set_hash)
+{
+ ASSERT_WRITE_LOCK(&ip_set_lock);
-+ IP_SET_ASSERT(ip_set_list[set_hash->binding]);
++ IP_SET_ASSERT(ip_set_list[set_hash->binding]);
+
+ __ip_set_put(set_hash->binding);
+ list_del(&set_hash->list);
+ u_int32_t key = jhash_2words(id, ip, ip_set_hash_random)
+ % ip_set_bindings_hash_size;
+ struct ip_set_hash *set_hash;
-+
++
+ IP_SET_ASSERT(ip_set_list[id]);
-+ DP("set: %s, ip: %u.%u.%u.%u", ip_set_list[id]->name, HIPQUAD(ip));
++ DP("set: %s, ip: %u.%u.%u.%u", ip_set_list[id]->name, HIPQUAD(ip));
+ write_lock_bh(&ip_set_lock);
+ set_hash = __ip_set_find(key, id, ip);
+ DP("set: %s, ip: %u.%u.%u.%u, binding: %s", ip_set_list[id]->name,
+ return 0;
+}
+
-+static int
++static int
+ip_set_hash_add(ip_set_id_t id, ip_set_ip_t ip, ip_set_id_t binding)
+{
+ u_int32_t key = jhash_2words(id, ip, ip_set_hash_random)
+ % ip_set_bindings_hash_size;
+ struct ip_set_hash *set_hash;
+ int ret = 0;
-+
++
+ IP_SET_ASSERT(ip_set_list[id]);
+ IP_SET_ASSERT(ip_set_list[binding]);
-+ DP("set: %s, ip: %u.%u.%u.%u, binding: %s", ip_set_list[id]->name,
++ DP("set: %s, ip: %u.%u.%u.%u, binding: %s", ip_set_list[id]->name,
+ HIPQUAD(ip), ip_set_list[binding]->name);
+ write_lock_bh(&ip_set_lock);
+ set_hash = __ip_set_find(key, id, ip);
+ set_hash->ip = ip;
+ list_add(&set_hash->list, &ip_set_hash[key]);
+ } else {
-+ IP_SET_ASSERT(ip_set_list[set_hash->binding]);
++ IP_SET_ASSERT(ip_set_list[set_hash->binding]);
+ DP("overwrite binding: %s",
+ ip_set_list[set_hash->binding]->name);
+ __ip_set_put(set_hash->binding);
+ ip_set_ip_t ip;
+ int res;
+ unsigned char i = 0;
-+
++
+ IP_SET_ASSERT(flags[i]);
+ read_lock_bh(&ip_set_lock);
+ do {
+ res = set->type->testip_kernel(set, skb, &ip, flags, i++);
+ read_unlock_bh(&set->lock);
+ i += !!(set->type->features & IPSET_DATA_DOUBLE);
-+ } while (res > 0
-+ && flags[i]
++ } while (res > 0
++ && flags[i]
+ && follow_bindings(index, set, ip));
+ read_unlock_bh(&ip_set_lock);
+
+ write_unlock_bh(&set->lock);
+ i += !!(set->type->features & IPSET_DATA_DOUBLE);
+ } while ((res == 0 || res == -EEXIST)
-+ && flags[i]
++ && flags[i]
+ && follow_bindings(index, set, ip));
+ read_unlock_bh(&ip_set_lock);
+
+ write_unlock_bh(&set->lock);
+ i += !!(set->type->features & IPSET_DATA_DOUBLE);
+ } while ((res == 0 || res == -EEXIST)
-+ && flags[i]
++ && flags[i]
+ && follow_bindings(index, set, ip));
+ read_unlock_bh(&ip_set_lock);
+}
+ return NULL;
+}
+
-+int
++int
+ip_set_register_set_type(struct ip_set_type *set_type)
+{
+ int ret = 0;
-+
++
+ if (set_type->protocol_version != IP_SET_PROTOCOL_VERSION) {
+ ip_set_printk("'%s' uses wrong protocol version %u (want %u)",
+ set_type->typename,
+ write_lock_bh(&ip_set_lock);
+ if (find_set_type(set_type->typename)) {
+ /* Duplicate! */
-+ ip_set_printk("'%s' already registered!",
++ ip_set_printk("'%s' already registered!",
+ set_type->typename);
+ ret = -EINVAL;
+ goto unlock;
+ip_set_get_byname(const char *name)
+{
+ ip_set_id_t i, index = IP_SET_INVALID_ID;
-+
++
+ down(&ip_set_app_mutex);
+ for (i = 0; i < ip_set_max; i++) {
+ if (ip_set_list[i] != NULL
+
+ if (index >= ip_set_max)
+ return IP_SET_INVALID_ID;
-+
++
+ if (ip_set_list[index])
+ __ip_set_get(index);
+ else
+ index = IP_SET_INVALID_ID;
-+
++
+ up(&ip_set_app_mutex);
+ return index;
+}
+ip_set_find_byname(const char *name)
+{
+ ip_set_id_t i, index = IP_SET_INVALID_ID;
-+
++
+ for (i = 0; i < ip_set_max; i++) {
+ if (ip_set_list[i] != NULL
+ && strcmp(ip_set_list[i]->name, name) == 0) {
+{
+ if (index >= ip_set_max || ip_set_list[index] == NULL)
+ index = IP_SET_INVALID_ID;
-+
++
+ return index;
+}
+
+ struct ip_set *set = ip_set_list[index];
+ ip_set_ip_t ip;
+ int res;
-+
++
+ IP_SET_ASSERT(set);
+ do {
+ write_lock_bh(&set->lock);
+ struct ip_set *set = ip_set_list[index];
+ ip_set_ip_t ip;
+ int res;
-+
++
+ IP_SET_ASSERT(set);
+ write_lock_bh(&set->lock);
+ res = set->type->delip(set,
+ IP_SET_ASSERT(set);
+ if (size < sizeof(struct ip_set_req_bind))
+ return -EINVAL;
-+
++
+ req_bind = (struct ip_set_req_bind *) data;
+ req_bind->binding[IP_SET_MAXNAMELEN - 1] = '\0';
+
+ if (strcmp(req_bind->binding, IPSET_TOKEN_DEFAULT) == 0) {
+ /* Default binding of a set */
+ char *binding_name;
-+
++
+ if (size != sizeof(struct ip_set_req_bind) + IP_SET_MAXNAMELEN)
+ return -EINVAL;
+
-+ binding_name = (char *)(data + sizeof(struct ip_set_req_bind));
++ binding_name = (char *)(data + sizeof(struct ip_set_req_bind));
+ binding_name[IP_SET_MAXNAMELEN - 1] = '\0';
+
+ binding = ip_set_find_byname(binding_name);
+ &ip);
+ DP("set %s, ip: %u.%u.%u.%u, binding %s",
+ set->name, HIPQUAD(ip), ip_set_list[binding]->name);
-+
++
+ if (res >= 0)
+ res = ip_set_hash_add(set->id, ip, binding);
+
+ DP("");
+ if (size < sizeof(struct ip_set_req_bind))
+ return -EINVAL;
-+
++
+ req_bind = (struct ip_set_req_bind *) data;
+ req_bind->binding[IP_SET_MAXNAMELEN - 1] = '\0';
-+
++
+ DP("%u %s", index, req_bind->binding);
+ if (index == IP_SET_INVALID_ID) {
+ /* unbind :all: */
+ DP("unreachable reached!");
+ return -EINVAL;
+ }
-+
++
+ set = ip_set_list[index];
+ IP_SET_ASSERT(set);
+ if (strcmp(req_bind->binding, IPSET_TOKEN_DEFAULT) == 0) {
+
+ if (binding == IP_SET_INVALID_ID)
+ return -ENOENT;
-+
++
+ write_lock_bh(&ip_set_lock);
+ /* Sets in hash values are referenced */
+ __ip_set_put(set->binding);
+ write_unlock_bh(&ip_set_lock);
+ return 0;
+ }
-+
++
+ res = __ip_set_testip(set,
+ data + sizeof(struct ip_set_req_bind),
+ size - sizeof(struct ip_set_req_bind),
+ IP_SET_ASSERT(set);
+ if (size < sizeof(struct ip_set_req_bind))
+ return -EINVAL;
-+
++
+ req_bind = (struct ip_set_req_bind *) data;
+ req_bind->binding[IP_SET_MAXNAMELEN - 1] = '\0';
+
+ if (strcmp(req_bind->binding, IPSET_TOKEN_DEFAULT) == 0) {
+ /* Default binding of set */
+ char *binding_name;
-+
++
+ if (size != sizeof(struct ip_set_req_bind) + IP_SET_MAXNAMELEN)
+ return -EINVAL;
+
-+ binding_name = (char *)(data + sizeof(struct ip_set_req_bind));
++ binding_name = (char *)(data + sizeof(struct ip_set_req_bind));
+ binding_name[IP_SET_MAXNAMELEN - 1] = '\0';
+
+ binding = ip_set_find_byname(binding_name);
+ if (binding == IP_SET_INVALID_ID)
+ return -ENOENT;
-+
++
+ res = (set->binding == binding) ? -EEXIST : 0;
+
+ return res;
+ binding = ip_set_find_byname(req_bind->binding);
+ if (binding == IP_SET_INVALID_ID)
+ return -ENOENT;
-+
-+
++
++
+ res = __ip_set_testip(set,
+ data + sizeof(struct ip_set_req_bind),
+ size - sizeof(struct ip_set_req_bind),
+ &ip);
+ DP("set %s, ip: %u.%u.%u.%u, binding %s",
+ set->name, HIPQUAD(ip), ip_set_list[binding]->name);
-+
++
+ if (res >= 0)
+ res = (ip_set_find_in_hash(set->id, ip) == binding)
+ ? -EEXIST : 0;
+find_set_type_rlock(const char *typename)
+{
+ struct ip_set_type *type;
-+
++
+ read_lock_bh(&ip_set_lock);
+ type = find_set_type(typename);
+ if (type == NULL)
+ /* No free slot remained */
+ return -ERANGE;
+ /* Check that index is usable as id (swapping) */
-+ check:
++ check:
+ for (i = 0; i < ip_set_max; i++) {
+ if (ip_set_list[i] != NULL
+ && ip_set_list[i]->id == *id) {
+
+ /*
+ * Here, we have a valid, constructed set. &ip_set_lock again,
-+ * find free id/index and check that it is not already in
++ * find free id/index and check that it is not already in
+ * ip_set_list.
+ */
+ write_lock_bh(&ip_set_lock);
+ res = -ERANGE;
+ goto cleanup;
+ }
-+
++
+ /*
+ * Finally! Add our shiny new set to the list, and be done.
+ */
+ ip_set_list[index] = set;
+ write_unlock_bh(&ip_set_lock);
+ return res;
-+
++
+ cleanup:
+ write_unlock_bh(&ip_set_lock);
+ set->type->destroy(set);
+ ip_set_destroy_set(index);
+ } else {
+ for (i = 0; i < ip_set_max; i++) {
-+ if (ip_set_list[i] != NULL
++ if (ip_set_list[i] != NULL
+ && (atomic_read(&ip_set_list[i]->ref)))
+ return -EBUSY;
+ }
+ write_unlock_bh(&set->lock);
+}
+
-+/*
++/*
+ * Flush data in a set - or in all sets
+ */
+static int
+ write_lock_bh(&ip_set_lock);
+ for (i = 0; i < ip_set_max; i++) {
+ if (ip_set_list[i] != NULL
-+ && strncmp(ip_set_list[i]->name,
++ && strncmp(ip_set_list[i]->name,
+ name,
+ IP_SET_MAXNAMELEN - 1) == 0) {
+ res = -EEXIST;
+ if (from->type->features != to->type->features)
+ return -ENOEXEC;
+
-+ /* No magic here: ref munging protected by the mutex */
++ /* No magic here: ref munging protected by the mutex */
+ write_lock_bh(&ip_set_lock);
+ strncpy(from_name, from->name, IP_SET_MAXNAMELEN);
+ from_ref = atomic_read(&from->ref);
+ atomic_set(&from->ref, atomic_read(&to->ref));
+ strncpy(to->name, from_name, IP_SET_MAXNAMELEN);
+ atomic_set(&to->ref, from_ref);
-+
++
+ ip_set_list[from_index] = to;
+ ip_set_list[to_index] = from;
-+
++
+ write_unlock_bh(&ip_set_lock);
+ return 0;
+}
+ ip_set_id_t id, void *data, int *used)
+{
+ if (set_hash->id == id) {
-+ struct ip_set_hash_list *hash_list =
++ struct ip_set_hash_list *hash_list =
+ (struct ip_set_hash_list *)(data + *used);
+
+ hash_list->ip = set_hash->ip;
+
+ /* Fill in set spefific bindings data */
+ FOREACH_HASH_DO(__set_hash_bindings, set->id, data, used);
-+
++
+ return 0;
+
+ unlock_set:
+ *used += sizeof(struct ip_set_save);
+
+ set = ip_set_list[index];
-+ DP("set: %s, used: %u(%u) %p %p", set->name, *used, len,
++ DP("set: %s, used: %u(%u) %p %p", set->name, *used, len,
+ data, data + *used);
+
+ read_lock_bh(&set->lock);
+{
+ if (*res == 0
+ && (id == IP_SET_INVALID_ID || set_hash->id == id)) {
-+ struct ip_set_hash_save *hash_save =
++ struct ip_set_hash_save *hash_save =
+ (struct ip_set_hash_save *)(data + *used);
+ /* Ensure bindings size */
+ if (*used + sizeof(struct ip_set_hash_save) > len) {
+ index = ip_set_list[index]->id;
+ FOREACH_HASH_DO(__set_hash_save_bindings, index, data, used, len, &res);
+
-+ return res;
++ return res;
+}
+
+/*
+ /* Loop to restore sets */
+ while (1) {
+ line++;
-+
++
+ DP("%u %u %u", used, sizeof(struct ip_set_restore), len);
+ /* Get and ensure header size */
+ if (used + sizeof(struct ip_set_restore) > len)
+ used += sizeof(struct ip_set_restore);
+
+ /* Ensure data size */
-+ if (used
-+ + set_restore->header_size
++ if (used
++ + set_restore->header_size
+ + set_restore->members_size > len)
+ return line;
+
+ line--;
+ goto bindings;
+ }
-+
++
+ /* Try to create the set */
+ DP("restore %s %s", set_restore->name, set_restore->typename);
+ res = ip_set_create(set_restore->name,
+ set_restore->index,
+ data + used,
+ set_restore->header_size);
-+
++
+ if (res != 0)
+ return line;
+ used += set_restore->header_size;
+ res = __ip_set_addip(index,
+ data + used + members_size,
+ set->type->reqsize);
-+ if (!(res == 0 || res == -EEXIST))
++ if (!(res == 0 || res == -EEXIST))
+ return line;
+ members_size += set->type->reqsize;
+ }
+ set_restore->members_size, members_size);
+ if (members_size != set_restore->members_size)
+ return line++;
-+ used += set_restore->members_size;
++ used += set_restore->members_size;
+ }
-+
++
+ bindings:
+ /* Loop to restore bindings */
+ while (used < len) {
+ line++;
+
-+ DP("restore binding, line %u", line);
++ DP("restore binding, line %u", line);
+ /* Get and ensure size */
+ if (used + sizeof(struct ip_set_hash_save) > len)
+ return line;
+ hash_save = (struct ip_set_hash_save *) (data + used);
+ used += sizeof(struct ip_set_hash_save);
-+
++
+ /* hash_save->id is used to store the index */
+ index = ip_set_find_byindex(hash_save->id);
+ DP("restore binding index %u, id %u, %u -> %u",
-+ index, hash_save->id, hash_save->ip, hash_save->binding);
++ index, hash_save->id, hash_save->ip, hash_save->binding);
+ if (index != hash_save->id)
+ return line;
+ if (ip_set_find_byindex(hash_save->binding) == IP_SET_INVALID_ID) {
+ set = ip_set_list[hash_save->id];
+ /* Null valued IP means default binding */
+ if (hash_save->ip)
-+ res = ip_set_hash_add(set->id,
++ res = ip_set_hash_add(set->id,
+ hash_save->ip,
+ hash_save->binding);
+ else {
+ }
+ if (used != len)
+ return line;
-+
-+ return 0;
++
++ return 0;
+}
+
+static int
+
+ op = (unsigned *)data;
+ DP("op=%x", *op);
-+
++
+ if (*op < IP_SET_OP_VERSION) {
+ /* Check the version at the beginning of operations */
+ struct ip_set_req_version *req_version =
+ case IP_SET_OP_CREATE:{
+ struct ip_set_req_create *req_create
+ = (struct ip_set_req_create *) data;
-+
++
+ if (len < sizeof(struct ip_set_req_create)) {
+ ip_set_printk("short CREATE data (want >=%zu, got %u)",
+ sizeof(struct ip_set_req_create), len);
+ case IP_SET_OP_DESTROY:{
+ struct ip_set_req_std *req_destroy
+ = (struct ip_set_req_std *) data;
-+
++
+ if (len != sizeof(struct ip_set_req_std)) {
+ ip_set_printk("invalid DESTROY data (want %zu, got %u)",
+ sizeof(struct ip_set_req_std), len);
+ goto done;
+ }
+ }
-+
++
+ res = ip_set_destroy(index);
+ goto done;
+ }
+
+ req_rename->name[IP_SET_MAXNAMELEN - 1] = '\0';
+ req_rename->typename[IP_SET_MAXNAMELEN - 1] = '\0';
-+
++
+ index = ip_set_find_byname(req_rename->name);
+ if (index == IP_SET_INVALID_ID) {
+ res = -ENOENT;
+ res = ip_set_swap(index, to_index);
+ goto done;
+ }
-+ default:
++ default:
+ break; /* Set identified by id */
+ }
-+
++
+ /* There we may have add/del/test/bind/unbind/test_bind operations */
+ if (*op < IP_SET_OP_ADD_IP || *op > IP_SET_OP_TEST_BIND_SET) {
+ res = -EBADMSG;
+ req_adt = (struct ip_set_req_adt *) data;
+
+ /* -U :all: :all:|:default: uses IP_SET_INVALID_ID */
-+ if (!(*op == IP_SET_OP_UNBIND_SET
++ if (!(*op == IP_SET_OP_UNBIND_SET
+ && req_adt->index == IP_SET_INVALID_ID)) {
+ index = ip_set_find_byindex(req_adt->index);
+ if (index == IP_SET_INVALID_ID) {
+ return res;
+}
+
-+static int
++static int
+ip_set_sockfn_get(struct sock *sk, int optval, void *user, int *len)
+{
+ int res = 0;
+ req_max_sets->set.index = IP_SET_INVALID_ID;
+ } else {
+ req_max_sets->set.name[IP_SET_MAXNAMELEN - 1] = '\0';
-+ req_max_sets->set.index =
++ req_max_sets->set.index =
+ ip_set_find_byname(req_max_sets->set.name);
+ if (req_max_sets->set.index == IP_SET_INVALID_ID) {
+ res = -ENOENT;
+ }
+ goto copy;
+ }
-+ case IP_SET_OP_LIST_SIZE:
++ case IP_SET_OP_LIST_SIZE:
+ case IP_SET_OP_SAVE_SIZE: {
+ struct ip_set_req_setnames *req_setnames
+ = (struct ip_set_req_setnames *) data;
+ for (i = 0; i < ip_set_max; i++) {
+ if (ip_set_list[i] == NULL)
+ continue;
-+ name_list = (struct ip_set_name_list *)
++ name_list = (struct ip_set_name_list *)
+ (data + used);
+ used += sizeof(struct ip_set_name_list);
+ if (used > copylen) {
+ + set->type->header_size
+ + set->type->list_members_size(set);
+ /* Sets are identified by id in the hash */
-+ FOREACH_HASH_DO(__set_hash_bindings_size_list,
++ FOREACH_HASH_DO(__set_hash_bindings_size_list,
+ set->id, &req_setnames->size);
+ break;
+ }
+ }
+ if (res == 0)
+ res = ip_set_save_bindings(index, data, &used, *len);
-+
++
+ if (res != 0)
+ goto done;
+ else if (copylen != used) {
+ ? ip_set_list[index]->name
+ : ":all:", copylen);
+ res = copy_to_user(user, data, copylen);
-+
++
+ done:
+ up(&ip_set_app_mutex);
+ vfree(data);
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
-+ * published by the Free Software Foundation.
++ * published by the Free Software Foundation.
+ */
+
+/* Kernel module implementing an ip hash set */
+ *hash_ip = ip & map->netmask;
+ DP("set: %s, ip:%u.%u.%u.%u, %u.%u.%u.%u, %u.%u.%u.%u",
+ set->name, HIPQUAD(ip), HIPQUAD(*hash_ip), HIPQUAD(map->netmask));
-+
++
+ for (i = 0; i < map->probes; i++) {
+ id = jhash_ip(map, i, *hash_ip) % map->hashsize;
+ DP("hash key: %u", id);
+testip(struct ip_set *set, const void *data, size_t size,
+ ip_set_ip_t *hash_ip)
+{
-+ struct ip_set_req_iphash *req =
++ struct ip_set_req_iphash *req =
+ (struct ip_set_req_iphash *) data;
+
+ if (size != sizeof(struct ip_set_req_iphash)) {
+}
+
+static int
-+testip_kernel(struct ip_set *set,
++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)
+{
+ return __testip(set,
-+ ntohl(flags[index] & IPSET_SRC
++ ntohl(flags[index] & IPSET_SRC
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
-+ ? ip_hdr(skb)->saddr
++ ? ip_hdr(skb)->saddr
+ : ip_hdr(skb)->daddr),
+#else
-+ ? skb->nh.iph->saddr
++ ? skb->nh.iph->saddr
+ : skb->nh.iph->daddr),
+#endif
+ hash_ip);
+ __u32 probe;
+ u_int16_t i;
+ ip_set_ip_t *elem;
-+
++
+ if (!ip || map->elements >= limit)
+ return -ERANGE;
+
+ *hash_ip = ip & map->netmask;
-+
++
+ for (i = 0; i < map->probes; i++) {
+ probe = jhash_ip(map, i, *hash_ip) % map->hashsize;
+ elem = HARRAY_ELEM(map->members, ip_set_ip_t *, probe);
+addip(struct ip_set *set, const void *data, size_t size,
+ ip_set_ip_t *hash_ip)
+{
-+ struct ip_set_req_iphash *req =
++ struct ip_set_req_iphash *req =
+ (struct ip_set_req_iphash *) data;
+
+ if (size != sizeof(struct ip_set_req_iphash)) {
+}
+
+static int
-+addip_kernel(struct ip_set *set,
++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)
+{
+ return __addip((struct ip_set_iphash *) set->data,
-+ ntohl(flags[index] & IPSET_SRC
++ ntohl(flags[index] & IPSET_SRC
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
-+ ? ip_hdr(skb)->saddr
++ ? ip_hdr(skb)->saddr
+ : ip_hdr(skb)->daddr),
+#else
-+ ? skb->nh.iph->saddr
++ ? skb->nh.iph->saddr
+ : skb->nh.iph->daddr),
+#endif
+ hash_ip);
+ u_int32_t i, hashsize = map->hashsize;
+ int res;
+ struct ip_set_iphash *tmp;
-+
++
+ if (map->resize == 0)
+ return -ERANGE;
+
+ again:
+ res = 0;
-+
++
+ /* Calculate new hash size */
+ hashsize += (hashsize * map->resize)/100;
+ if (hashsize == map->hashsize)
+ hashsize++;
-+
++
+ ip_set_printk("rehashing of set %s triggered: "
+ "hashsize grows from %u to %u",
+ set->name, map->hashsize, hashsize);
+
-+ tmp = kmalloc(sizeof(struct ip_set_iphash)
++ tmp = kmalloc(sizeof(struct ip_set_iphash)
+ + map->probes * sizeof(uint32_t), GFP_ATOMIC);
+ if (!tmp) {
+ DP("out of memory for %d bytes",
+ tmp->resize = map->resize;
+ tmp->netmask = map->netmask;
+ memcpy(tmp->initval, map->initval, map->probes * sizeof(uint32_t));
-+
++
+ write_lock_bh(&set->lock);
+ map = (struct ip_set_iphash *) set->data; /* Play safe */
+ for (i = 0; i < map->hashsize && res == 0; i++) {
-+ elem = HARRAY_ELEM(map->members, ip_set_ip_t *, i);
++ elem = HARRAY_ELEM(map->members, ip_set_ip_t *, i);
+ if (*elem)
+ res = __addip(tmp, *elem, &hash_ip);
+ }
+ kfree(tmp);
+ goto again;
+ }
-+
++
+ /* Success at resizing! */
+ members = map->members;
+
+ id = hash_id(set, ip, hash_ip);
+ if (id == UINT_MAX)
+ return -EEXIST;
-+
++
+ elem = HARRAY_ELEM(map->members, ip_set_ip_t *, id);
+ *elem = 0;
+ map->elements--;
+}
+
+static int
-+delip_kernel(struct ip_set *set,
++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)
+{
+ return __delip(set,
-+ ntohl(flags[index] & IPSET_SRC
++ ntohl(flags[index] & IPSET_SRC
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
-+ ? ip_hdr(skb)->saddr
++ ? ip_hdr(skb)->saddr
+ : ip_hdr(skb)->daddr),
+#else
-+ ? skb->nh.iph->saddr
++ ? skb->nh.iph->saddr
+ : skb->nh.iph->daddr),
+#endif
+ hash_ip);
+ return -ENOEXEC;
+ }
+
-+ map = kmalloc(sizeof(struct ip_set_iphash)
++ map = kmalloc(sizeof(struct ip_set_iphash)
+ + req->probes * sizeof(uint32_t), GFP_KERNEL);
+ if (!map) {
+ DP("out of memory for %d bytes",
+ ip_set_ip_t i, *elem;
+
+ for (i = 0; i < map->hashsize; i++) {
-+ elem = HARRAY_ELEM(map->members, ip_set_ip_t *, i);
++ elem = HARRAY_ELEM(map->members, ip_set_ip_t *, i);
+ ((ip_set_ip_t *)data)[i] = *elem;
+ }
+}
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
-+ * published by the Free Software Foundation.
++ * published by the Free Software Foundation.
+ */
+
+/* Kernel module implementing an IP set type: the single bitmap type */
+__testip(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip)
+{
+ struct ip_set_ipmap *map = (struct ip_set_ipmap *) set->data;
-+
++
+ if (ip < map->first_ip || ip > map->last_ip)
+ return -ERANGE;
+
+testip(struct ip_set *set, const void *data, size_t size,
+ ip_set_ip_t *hash_ip)
+{
-+ struct ip_set_req_ipmap *req =
++ struct ip_set_req_ipmap *req =
+ (struct ip_set_req_ipmap *) data;
+
+ if (size != sizeof(struct ip_set_req_ipmap)) {
+}
+
+static int
-+testip_kernel(struct ip_set *set,
++testip_kernel(struct ip_set *set,
+ const struct sk_buff *skb,
+ ip_set_ip_t *hash_ip,
+ const u_int32_t *flags,
+ int res = __testip(set,
+ ntohl(flags[index] & IPSET_SRC
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
-+ ? ip_hdr(skb)->saddr
++ ? ip_hdr(skb)->saddr
+ : ip_hdr(skb)->daddr),
+#else
-+ ? skb->nh.iph->saddr
++ ? skb->nh.iph->saddr
+ : skb->nh.iph->daddr),
+#endif
+ hash_ip);
+addip(struct ip_set *set, const void *data, size_t size,
+ ip_set_ip_t *hash_ip)
+{
-+ struct ip_set_req_ipmap *req =
++ struct ip_set_req_ipmap *req =
+ (struct ip_set_req_ipmap *) data;
+
+ if (size != sizeof(struct ip_set_req_ipmap)) {
+}
+
+static int
-+addip_kernel(struct ip_set *set,
++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)
+{
+ return __addip(set,
-+ ntohl(flags[index] & IPSET_SRC
++ ntohl(flags[index] & IPSET_SRC
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
-+ ? ip_hdr(skb)->saddr
++ ? ip_hdr(skb)->saddr
+ : ip_hdr(skb)->daddr),
+#else
-+ ? skb->nh.iph->saddr
++ ? skb->nh.iph->saddr
+ : skb->nh.iph->daddr),
+#endif
+ hash_ip);
+}
+
-+static inline int
++static inline int
+__delip(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip)
+{
+ struct ip_set_ipmap *map = (struct ip_set_ipmap *) set->data;
+ DP("%u.%u.%u.%u, %u.%u.%u.%u", HIPQUAD(ip), HIPQUAD(*hash_ip));
+ if (!test_and_clear_bit(ip_to_id(map, *hash_ip), map->members))
+ return -EEXIST;
-+
++
+ return 0;
+}
+
+ unsigned char index)
+{
+ return __delip(set,
-+ ntohl(flags[index] & IPSET_SRC
++ ntohl(flags[index] & IPSET_SRC
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
-+ ? ip_hdr(skb)->saddr
++ ? ip_hdr(skb)->saddr
+ : ip_hdr(skb)->daddr),
+#else
-+ ? skb->nh.iph->saddr
++ ? skb->nh.iph->saddr
+ : skb->nh.iph->daddr),
+#endif
+ hash_ip);
+ } else {
+ unsigned int mask_bits, netmask_bits;
+ ip_set_ip_t mask;
-+
++
+ map->first_ip &= map->netmask; /* Should we better bark? */
-+
++
+ mask = range_to_mask(map->first_ip, map->last_ip, &mask_bits);
+ netmask_bits = mask_to_bits(map->netmask);
-+
++
+ if ((!mask && (map->first_ip || map->last_ip != 0xFFFFFFFF))
+ || netmask_bits <= mask_bits)
+ return -ENOEXEC;
+ return -ENOMEM;
+ }
+ memset(map->members, 0, newbytes);
-+
++
+ set->data = map;
+ return 0;
+}
+static void destroy(struct ip_set *set)
+{
+ struct ip_set_ipmap *map = (struct ip_set_ipmap *) set->data;
-+
++
+ kfree(map->members);
+ kfree(map);
-+
++
+ set->data = NULL;
+}
+
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
-+ * published by the Free Software Foundation.
++ * published by the Free Software Foundation.
+ */
+
+/* Kernel module implementing an ip+port hash set */
+ switch (iph->protocol) {
+ case IPPROTO_TCP: {
+ struct tcphdr tcph;
-+
++
+ /* See comments at tcp_match in ip_tables.c */
+ if (offset)
+ return INVALID_PORT;
+#endif
+ /* No choice either */
+ return INVALID_PORT;
-+
++
+ return ntohs(flags & IPSET_SRC ?
+ tcph.source : tcph.dest);
+ }
+#endif
+ /* No choice either */
+ return INVALID_PORT;
-+
++
+ return ntohs(flags & IPSET_SRC ?
+ udph.source : udph.dest);
+ }
+hash_id(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t port,
+ ip_set_ip_t *hash_ip)
+{
-+ struct ip_set_ipporthash *map =
++ struct ip_set_ipporthash *map =
+ (struct ip_set_ipporthash *) set->data;
+ __u32 id;
+ u_int16_t i;
+ *hash_ip = HASH_IP(map, ip, port);
+ DP("set: %s, ipport:%u.%u.%u.%u:%u, %u.%u.%u.%u",
+ set->name, HIPQUAD(ip), port, HIPQUAD(*hash_ip));
-+
++
+ for (i = 0; i < map->probes; i++) {
+ id = jhash_ip(map, i, *hash_ip) % map->hashsize;
+ DP("hash key: %u", id);
+ ip_set_ip_t *hash_ip)
+{
+ struct ip_set_ipporthash *map = (struct ip_set_ipporthash *) set->data;
-+
++
+ if (ip < map->first_ip || ip > map->last_ip)
+ return -ERANGE;
+
+testip(struct ip_set *set, const void *data, size_t size,
+ ip_set_ip_t *hash_ip)
+{
-+ struct ip_set_req_ipporthash *req =
++ struct ip_set_req_ipporthash *req =
+ (struct ip_set_req_ipporthash *) data;
+
+ if (size != sizeof(struct ip_set_req_ipporthash)) {
+}
+
+static int
-+testip_kernel(struct ip_set *set,
++testip_kernel(struct ip_set *set,
+ const struct sk_buff *skb,
+ ip_set_ip_t *hash_ip,
+ const u_int32_t *flags,
+
+ if (flags[index+1] == 0)
+ return 0;
-+
++
+ port = get_port(skb, flags[index+1]);
+
+ DP("flag: %s src: %u.%u.%u.%u dst: %u.%u.%u.%u",
+ NIPQUAD(skb->nh.iph->daddr));
+#endif
+ DP("flag %s port %u",
-+ flags[index+1] & IPSET_SRC ? "SRC" : "DST",
-+ port);
++ flags[index+1] & IPSET_SRC ? "SRC" : "DST",
++ port);
+ if (port == INVALID_PORT)
-+ return 0;
++ return 0;
+
+ res = __testip(set,
-+ ntohl(flags[index] & IPSET_SRC
++ ntohl(flags[index] & IPSET_SRC
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
-+ ? ip_hdr(skb)->saddr
++ ? ip_hdr(skb)->saddr
+ : ip_hdr(skb)->daddr),
+#else
-+ ? skb->nh.iph->saddr
++ ? skb->nh.iph->saddr
+ : skb->nh.iph->daddr),
+#endif
+ port,
+ hash_ip);
+ return (res < 0 ? 0 : res);
-+
++
+}
+
+static inline int
+ return -ERANGE;
+
+ *hash_ip = HASH_IP(map, ip, port);
-+
++
+ return __add_haship(map, *hash_ip);
+}
+
+addip(struct ip_set *set, const void *data, size_t size,
+ ip_set_ip_t *hash_ip)
+{
-+ struct ip_set_req_ipporthash *req =
++ struct ip_set_req_ipporthash *req =
+ (struct ip_set_req_ipporthash *) data;
+
+ if (size != sizeof(struct ip_set_req_ipporthash)) {
+ size);
+ return -EINVAL;
+ }
-+ return __addip((struct ip_set_ipporthash *) set->data,
++ return __addip((struct ip_set_ipporthash *) set->data,
+ req->ip, req->port, hash_ip);
+}
+
+static int
-+addip_kernel(struct ip_set *set,
++addip_kernel(struct ip_set *set,
+ const struct sk_buff *skb,
+ ip_set_ip_t *hash_ip,
+ const u_int32_t *flags,
+
+ if (flags[index+1] == 0)
+ return -EINVAL;
-+
++
+ port = get_port(skb, flags[index+1]);
+
+ DP("flag: %s src: %u.%u.%u.%u dst: %u.%u.%u.%u",
+ NIPQUAD(skb->nh.iph->saddr),
+ NIPQUAD(skb->nh.iph->daddr));
+#endif
-+ DP("flag %s port %u",
-+ flags[index+1] & IPSET_SRC ? "SRC" : "DST",
-+ port);
++ DP("flag %s port %u",
++ flags[index+1] & IPSET_SRC ? "SRC" : "DST",
++ port);
+ if (port == INVALID_PORT)
-+ return -EINVAL;
++ return -EINVAL;
+
+ return __addip((struct ip_set_ipporthash *) set->data,
-+ ntohl(flags[index] & IPSET_SRC
++ ntohl(flags[index] & IPSET_SRC
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
-+ ? ip_hdr(skb)->saddr
++ ? ip_hdr(skb)->saddr
+ : ip_hdr(skb)->daddr),
+#else
-+ ? skb->nh.iph->saddr
++ ? skb->nh.iph->saddr
+ : skb->nh.iph->daddr),
+#endif
+ port,
+ u_int32_t i, hashsize = map->hashsize;
+ int res;
+ struct ip_set_ipporthash *tmp;
-+
++
+ if (map->resize == 0)
+ return -ERANGE;
+
+ again:
+ res = 0;
-+
++
+ /* Calculate new hash size */
+ hashsize += (hashsize * map->resize)/100;
+ if (hashsize == map->hashsize)
+ hashsize++;
-+
++
+ ip_set_printk("rehashing of set %s triggered: "
+ "hashsize grows from %u to %u",
+ set->name, map->hashsize, hashsize);
+
-+ tmp = kmalloc(sizeof(struct ip_set_ipporthash)
++ tmp = kmalloc(sizeof(struct ip_set_ipporthash)
+ + map->probes * sizeof(uint32_t), GFP_ATOMIC);
+ if (!tmp) {
+ DP("out of memory for %d bytes",
+ tmp->first_ip = map->first_ip;
+ tmp->last_ip = map->last_ip;
+ memcpy(tmp->initval, map->initval, map->probes * sizeof(uint32_t));
-+
++
+ write_lock_bh(&set->lock);
+ map = (struct ip_set_ipporthash *) set->data; /* Play safe */
+ for (i = 0; i < map->hashsize && res == 0; i++) {
-+ elem = HARRAY_ELEM(map->members, ip_set_ip_t *, i);
++ elem = HARRAY_ELEM(map->members, ip_set_ip_t *, i);
+ if (*elem)
+ res = __add_haship(tmp, *elem);
+ }
+ kfree(tmp);
+ goto again;
+ }
-+
++
+ /* Success at resizing! */
+ members = map->members;
+
+
+ if (id == UINT_MAX)
+ return -EEXIST;
-+
++
+ elem = HARRAY_ELEM(map->members, ip_set_ip_t *, id);
+ *elem = 0;
+ map->elements--;
+}
+
+static int
-+delip_kernel(struct ip_set *set,
++delip_kernel(struct ip_set *set,
+ const struct sk_buff *skb,
+ ip_set_ip_t *hash_ip,
+ const u_int32_t *flags,
+
+ if (flags[index+1] == 0)
+ return -EINVAL;
-+
++
+ port = get_port(skb, flags[index+1]);
+
+ DP("flag: %s src: %u.%u.%u.%u dst: %u.%u.%u.%u",
+ NIPQUAD(skb->nh.iph->daddr));
+#endif
+ DP("flag %s port %u",
-+ flags[index+1] & IPSET_SRC ? "SRC" : "DST",
-+ port);
++ flags[index+1] & IPSET_SRC ? "SRC" : "DST",
++ port);
+ if (port == INVALID_PORT)
-+ return -EINVAL;
++ return -EINVAL;
+
+ return __delip(set,
-+ ntohl(flags[index] & IPSET_SRC
++ ntohl(flags[index] & IPSET_SRC
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
-+ ? ip_hdr(skb)->saddr
++ ? ip_hdr(skb)->saddr
+ : ip_hdr(skb)->daddr),
+#else
-+ ? skb->nh.iph->saddr
++ ? skb->nh.iph->saddr
+ : skb->nh.iph->daddr),
+#endif
+ port,
+ return -ENOEXEC;
+ }
+
-+ map = kmalloc(sizeof(struct ip_set_ipporthash)
++ map = kmalloc(sizeof(struct ip_set_ipporthash)
+ + req->probes * sizeof(uint32_t), GFP_KERNEL);
+ if (!map) {
+ DP("out of memory for %d bytes",
+ ip_set_ip_t i, *elem;
+
+ for (i = 0; i < map->hashsize; i++) {
-+ elem = HARRAY_ELEM(map->members, ip_set_ip_t *, i);
++ elem = HARRAY_ELEM(map->members, ip_set_ip_t *, i);
+ ((ip_set_ip_t *)data)[i] = *elem;
+ }
+}
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
-+ * published by the Free Software Foundation.
++ * published by the Free Software Foundation.
+ */
+
+/* Kernel module implementing an IP set type: the iptree type */
+
+/* Garbage collection interval in seconds: */
+#define IPTREE_GC_TIME 5*60
-+/* Sleep so many milliseconds before trying again
-+ * to delete the gc timer at destroying/flushing a set */
++/* Sleep so many milliseconds before trying again
++ * to delete the gc timer at destroying/flushing a set */
+#define IPTREE_DESTROY_SLEEP 100
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21)
+
+ if (!ip)
+ return -ERANGE;
-+
++
+ *hash_ip = ip;
+ ABCD(a, b, c, d, hash_ip);
+ DP("%u %u %u %u timeout %u", a, b, c, d, map->timeout);
+testip(struct ip_set *set, const void *data, size_t size,
+ ip_set_ip_t *hash_ip)
+{
-+ struct ip_set_req_iptree *req =
++ struct ip_set_req_iptree *req =
+ (struct ip_set_req_iptree *) data;
+
+ if (size != sizeof(struct ip_set_req_iptree)) {
+}
+
+static int
-+testip_kernel(struct ip_set *set,
++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)
+{
+ int res;
-+
++
+ DP("flag: %s src: %u.%u.%u.%u dst: %u.%u.%u.%u",
+ flags[index] & IPSET_SRC ? "SRC" : "DST",
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
+#endif
+
+ res = __testip(set,
-+ ntohl(flags[index] & IPSET_SRC
++ ntohl(flags[index] & IPSET_SRC
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
-+ ? ip_hdr(skb)->saddr
++ ? ip_hdr(skb)->saddr
+ : ip_hdr(skb)->daddr),
+#else
-+ ? skb->nh.iph->saddr
++ ? skb->nh.iph->saddr
+ : skb->nh.iph->daddr),
+#endif
+ hash_ip);
+ (map)->tree[elem] = branch; \
+ DP("alloc %u", elem); \
+ } \
-+} while (0)
++} while (0)
+
+static inline int
+__addip(struct ip_set *set, ip_set_ip_t ip, unsigned int timeout,
+ struct ip_set_iptreed *dtree;
+ unsigned char a,b,c,d;
+ int ret = 0;
-+
++
+ if (!ip || map->elements >= limit)
+ /* We could call the garbage collector
+ * but it's probably overkill */
+ return -ERANGE;
-+
++
+ *hash_ip = ip;
+ ABCD(a, b, c, d, hash_ip);
+ DP("%u %u %u %u timeout %u", a, b, c, d, timeout);
+ ip_set_ip_t *hash_ip)
+{
+ struct ip_set_iptree *map = (struct ip_set_iptree *) set->data;
-+ struct ip_set_req_iptree *req =
++ struct ip_set_req_iptree *req =
+ (struct ip_set_req_iptree *) data;
+
+ if (size != sizeof(struct ip_set_req_iptree)) {
+}
+
+static int
-+addip_kernel(struct ip_set *set,
++addip_kernel(struct ip_set *set,
+ const struct sk_buff *skb,
+ ip_set_ip_t *hash_ip,
+ const u_int32_t *flags,
+ struct ip_set_iptree *map = (struct ip_set_iptree *) set->data;
+
+ return __addip(set,
-+ ntohl(flags[index] & IPSET_SRC
++ ntohl(flags[index] & IPSET_SRC
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
-+ ? ip_hdr(skb)->saddr
++ ? ip_hdr(skb)->saddr
+ : ip_hdr(skb)->daddr),
+#else
-+ ? skb->nh.iph->saddr
++ ? skb->nh.iph->saddr
+ : skb->nh.iph->daddr),
+#endif
+ map->timeout,
+ return -EEXIST; \
+} while (0)
+
-+static inline int
++static inline int
+__delip(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip)
+{
+ struct ip_set_iptree *map = (struct ip_set_iptree *) set->data;
+ struct ip_set_iptreec *ctree;
+ struct ip_set_iptreed *dtree;
+ unsigned char a,b,c,d;
-+
++
+ if (!ip)
+ return -ERANGE;
-+
++
+ *hash_ip = ip;
+ ABCD(a, b, c, d, hash_ip);
+ DELIP_WALK(map, a, btree);
+}
+
+static int
-+delip_kernel(struct ip_set *set,
++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)
+{
+ return __delip(set,
-+ ntohl(flags[index] & IPSET_SRC
++ ntohl(flags[index] & IPSET_SRC
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
-+ ? ip_hdr(skb)->saddr
++ ? ip_hdr(skb)->saddr
+ : ip_hdr(skb)->daddr),
+#else
-+ ? skb->nh.iph->saddr
++ ? skb->nh.iph->saddr
+ : skb->nh.iph->daddr),
+#endif
+ hash_ip);
+ }
+ LOOP_WALK_END;
+ write_unlock_bh(&set->lock);
-+
++
+ map->gc.expires = jiffies + map->gc_interval * HZ;
+ add_timer(&map->gc);
+}
+{
+ struct ip_set_iptree *map = (struct ip_set_iptree *) set->data;
+ unsigned int timeout = map->timeout;
-+
++
+ /* gc might be running */
+ while (!del_timer(&map->gc))
+ msleep(IPTREE_DESTROY_SLEEP);
+ && (!map->timeout || time_after(dtree->expires[d], jiffies))) {
+ entry = (struct ip_set_req_iptree *)(data + offset);
+ entry->ip = ((a << 24) | (b << 16) | (c << 8) | d);
-+ entry->timeout = !map->timeout ? 0
++ entry->timeout = !map->timeout ? 0
+ : (dtree->expires[d] - jiffies)/HZ;
+ offset += sizeof(struct ip_set_req_iptree);
+ }
+static int __init ip_set_iptree_init(void)
+{
+ int ret;
-+
++
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,23)
+ branch_cachep = kmem_cache_create("ip_set_iptreeb",
+ sizeof(struct ip_set_iptreeb),
+ goto out;
+
+ kmem_cache_destroy(leaf_cachep);
-+ free_branch:
++ free_branch:
+ kmem_cache_destroy(branch_cachep);
+ out:
+ return ret;
+{
+ int res;
+
-+ res = __testip(set,
-+ ntohl(flags[index] & IPSET_SRC
++ res = __testip(set,
++ ntohl(flags[index] & IPSET_SRC
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
-+ ? ip_hdr(skb)->saddr
++ ? ip_hdr(skb)->saddr
+ : ip_hdr(skb)->daddr),
+#else
-+ ? skb->nh.iph->saddr
++ ? skb->nh.iph->saddr
+ : skb->nh.iph->daddr),
+#endif
+ hash_ip);
+{
+
+ return __addip_single(set,
-+ ntohl(flags[index] & IPSET_SRC
++ ntohl(flags[index] & IPSET_SRC
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
-+ ? ip_hdr(skb)->saddr
++ ? ip_hdr(skb)->saddr
+ : ip_hdr(skb)->daddr),
+#else
-+ ? skb->nh.iph->saddr
++ ? skb->nh.iph->saddr
+ : skb->nh.iph->daddr),
+#endif
+ hash_ip);
+static int
+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)
+{
-+ return __delip_single(set,
-+ ntohl(flags[index] & IPSET_SRC
++ return __delip_single(set,
++ ntohl(flags[index] & IPSET_SRC
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
-+ ? ip_hdr(skb)->saddr
++ ? ip_hdr(skb)->saddr
+ : ip_hdr(skb)->daddr),
+#else
-+ ? skb->nh.iph->saddr
++ ? skb->nh.iph->saddr
+ : skb->nh.iph->daddr),
+#endif
+ hash_ip,
+ int a;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,23)
-+ cachep_b = kmem_cache_create("ip_set_iptreemap_b",
-+ sizeof(struct ip_set_iptreemap_b),
++ cachep_b = kmem_cache_create("ip_set_iptreemap_b",
++ sizeof(struct ip_set_iptreemap_b),
+ 0, 0, NULL);
+#else
-+ cachep_b = kmem_cache_create("ip_set_iptreemap_b",
-+ sizeof(struct ip_set_iptreemap_b),
++ cachep_b = kmem_cache_create("ip_set_iptreemap_b",
++ sizeof(struct ip_set_iptreemap_b),
+ 0, 0, NULL, NULL);
+#endif
+ if (!cachep_b) {
+ }
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,23)
-+ cachep_c = kmem_cache_create("ip_set_iptreemap_c",
++ cachep_c = kmem_cache_create("ip_set_iptreemap_c",
+ sizeof(struct ip_set_iptreemap_c),
+ 0, 0, NULL);
+#else
-+ cachep_c = kmem_cache_create("ip_set_iptreemap_c",
++ cachep_c = kmem_cache_create("ip_set_iptreemap_c",
+ sizeof(struct ip_set_iptreemap_c),
+ 0, 0, NULL, NULL);
+#endif
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
-+ * published by the Free Software Foundation.
++ * published by the Free Software Foundation.
+ */
+
+/* Kernel module implementing an IP set type: the macipmap type */
+testip(struct ip_set *set, const void *data, size_t size, ip_set_ip_t *hash_ip)
+{
+ struct ip_set_macipmap *map = (struct ip_set_macipmap *) set->data;
-+ struct ip_set_macip *table = (struct ip_set_macip *) map->members;
++ struct ip_set_macip *table = (struct ip_set_macip *) map->members;
+ struct ip_set_req_macipmap *req = (struct ip_set_req_macipmap *) data;
+
+ if (size != sizeof(struct ip_set_req_macipmap)) {
+
+ *hash_ip = req->ip;
+ DP("set: %s, ip:%u.%u.%u.%u, %u.%u.%u.%u",
-+ set->name, HIPQUAD(req->ip), HIPQUAD(*hash_ip));
++ set->name, HIPQUAD(req->ip), HIPQUAD(*hash_ip));
+ if (test_bit(IPSET_MACIP_ISSET,
+ (void *) &table[req->ip - map->first_ip].flags)) {
+ return (memcmp(req->ethernet,
+}
+
+static int
-+testip_kernel(struct ip_set *set,
++testip_kernel(struct ip_set *set,
+ const struct sk_buff *skb,
+ ip_set_ip_t *hash_ip,
+ const u_int32_t *flags,
+ struct ip_set_macip *table =
+ (struct ip_set_macip *) map->members;
+ ip_set_ip_t ip;
-+
++
+ ip = ntohl(flags[index] & IPSET_SRC
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
-+ ? ip_hdr(skb)->saddr
++ ? ip_hdr(skb)->saddr
+ : ip_hdr(skb)->daddr);
+#else
+ ? skb->nh.iph->saddr
+ if (ip < map->first_ip || ip > map->last_ip)
+ return 0;
+
-+ *hash_ip = ip;
++ *hash_ip = ip;
+ DP("set: %s, ip:%u.%u.%u.%u, %u.%u.%u.%u",
-+ set->name, HIPQUAD(ip), HIPQUAD(*hash_ip));
++ set->name, HIPQUAD(ip), HIPQUAD(*hash_ip));
+ if (test_bit(IPSET_MACIP_ISSET,
+ (void *) &table[ip - map->first_ip].flags)) {
+ /* Is mac pointer valid?
+
+/* returns 0 on success */
+static inline int
-+__addip(struct ip_set *set,
++__addip(struct ip_set *set,
+ ip_set_ip_t ip, unsigned char *ethernet, ip_set_ip_t *hash_ip)
+{
+ struct ip_set_macipmap *map =
+
+ if (ip < map->first_ip || ip > map->last_ip)
+ return -ERANGE;
-+ if (test_and_set_bit(IPSET_MACIP_ISSET,
++ if (test_and_set_bit(IPSET_MACIP_ISSET,
+ (void *) &table[ip - map->first_ip].flags))
+ return -EEXIST;
+
+}
+
+static int
-+addip_kernel(struct ip_set *set,
++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)
+{
+ ip_set_ip_t ip;
-+
++
+ ip = ntohl(flags[index] & IPSET_SRC
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
-+ ? ip_hdr(skb)->saddr
++ ? ip_hdr(skb)->saddr
+ : ip_hdr(skb)->daddr);
+#else
+ ? skb->nh.iph->saddr
+
+ if (ip < map->first_ip || ip > map->last_ip)
+ return -ERANGE;
-+ if (!test_and_clear_bit(IPSET_MACIP_ISSET,
++ if (!test_and_clear_bit(IPSET_MACIP_ISSET,
+ (void *)&table[ip - map->first_ip].flags))
+ return -EEXIST;
+
+ unsigned char index)
+{
+ return __delip(set,
-+ ntohl(flags[index] & IPSET_SRC
++ ntohl(flags[index] & IPSET_SRC
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
-+ ? ip_hdr(skb)->saddr
++ ? ip_hdr(skb)->saddr
+ : ip_hdr(skb)->daddr),
+#else
-+ ? skb->nh.iph->saddr
++ ? skb->nh.iph->saddr
+ : skb->nh.iph->daddr),
+#endif
+ hash_ip);
+ return -ENOMEM;
+ }
+ memset(map->members, 0, newbytes);
-+
++
+ set->data = map;
+ return 0;
+}
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
-+ * published by the Free Software Foundation.
++ * published by the Free Software Foundation.
+ */
+
+/* Kernel module implementing a cidr nethash set */
+ ip_set_ip_t *elem;
+
+ *hash_ip = pack(ip, cidr);
-+
++
+ for (i = 0; i < map->probes; i++) {
+ id = jhash_ip(map, i, *hash_ip) % map->hashsize;
+ DP("hash key: %u", id);
+testip(struct ip_set *set, const void *data, size_t size,
+ ip_set_ip_t *hash_ip)
+{
-+ struct ip_set_req_nethash *req =
++ struct ip_set_req_nethash *req =
+ (struct ip_set_req_nethash *) data;
+
+ if (size != sizeof(struct ip_set_req_nethash)) {
+}
+
+static int
-+testip_kernel(struct ip_set *set,
++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)
+{
+ return __testip(set,
-+ ntohl(flags[index] & IPSET_SRC
++ ntohl(flags[index] & IPSET_SRC
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
-+ ? ip_hdr(skb)->saddr
++ ? ip_hdr(skb)->saddr
+ : ip_hdr(skb)->daddr),
+#else
-+ ? skb->nh.iph->saddr
++ ? skb->nh.iph->saddr
+ : skb->nh.iph->daddr),
+#endif
+ hash_ip);
+ __u32 probe;
+ u_int16_t i;
+ ip_set_ip_t *elem;
-+
++
+ for (i = 0; i < map->probes; i++) {
+ probe = jhash_ip(map, i, ip) % map->hashsize;
+ elem = HARRAY_ELEM(map->members, ip_set_ip_t *, probe);
+{
+ if (!ip || map->elements >= limit)
+ return -ERANGE;
-+
++
+ *hash_ip = pack(ip, cidr);
+ DP("%u.%u.%u.%u/%u, %u.%u.%u.%u", HIPQUAD(ip), cidr, HIPQUAD(*hash_ip));
-+
++
+ return __addip_base(map, *hash_ip);
+}
+
+{
+ unsigned char next;
+ int i;
-+
++
+ for (i = 0; i < 30 && map->cidr[i]; i++) {
+ if (map->cidr[i] == cidr) {
+ return;
+addip(struct ip_set *set, const void *data, size_t size,
+ ip_set_ip_t *hash_ip)
+{
-+ struct ip_set_req_nethash *req =
++ struct ip_set_req_nethash *req =
+ (struct ip_set_req_nethash *) data;
+ int ret;
+
+ size);
+ return -EINVAL;
+ }
-+ ret = __addip((struct ip_set_nethash *) set->data,
++ ret = __addip((struct ip_set_nethash *) set->data,
+ req->ip, req->cidr, hash_ip);
-+
++
+ if (ret == 0)
+ update_cidr_sizes((struct ip_set_nethash *) set->data,
+ req->cidr);
-+
++
+ return ret;
+}
+
+static int
-+addip_kernel(struct ip_set *set,
++addip_kernel(struct ip_set *set,
+ const struct sk_buff *skb,
+ ip_set_ip_t *hash_ip,
+ const u_int32_t *flags,
+{
+ struct ip_set_nethash *map = (struct ip_set_nethash *) set->data;
+ int ret = -ERANGE;
-+ ip_set_ip_t ip = ntohl(flags[index] & IPSET_SRC
++ ip_set_ip_t ip = ntohl(flags[index] & IPSET_SRC
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
-+ ? ip_hdr(skb)->saddr
++ ? ip_hdr(skb)->saddr
+ : ip_hdr(skb)->daddr);
+#else
+ ? skb->nh.iph->saddr
+ : skb->nh.iph->daddr);
+#endif
-+
++
+ if (map->cidr[0])
+ ret = __addip(map, ip, map->cidr[0], hash_ip);
-+
++
+ return ret;
+}
+
+ u_int32_t i, hashsize = map->hashsize;
+ int res;
+ struct ip_set_nethash *tmp;
-+
++
+ if (map->resize == 0)
+ return -ERANGE;
+
+ again:
+ res = 0;
-+
++
+ /* Calculate new parameters */
+ hashsize += (hashsize * map->resize)/100;
+ if (hashsize == map->hashsize)
+ hashsize++;
-+
++
+ ip_set_printk("rehashing of set %s triggered: "
+ "hashsize grows from %u to %u",
+ set->name, map->hashsize, hashsize);
+
-+ tmp = kmalloc(sizeof(struct ip_set_nethash)
++ tmp = kmalloc(sizeof(struct ip_set_nethash)
+ + map->probes * sizeof(uint32_t), GFP_ATOMIC);
+ if (!tmp) {
+ DP("out of memory for %d bytes",
+ tmp->resize = map->resize;
+ memcpy(tmp->initval, map->initval, map->probes * sizeof(uint32_t));
+ memcpy(tmp->cidr, map->cidr, 30 * sizeof(unsigned char));
-+
++
+ write_lock_bh(&set->lock);
+ map = (struct ip_set_nethash *) set->data; /* Play safe */
+ for (i = 0; i < map->hashsize && res == 0; i++) {
-+ elem = HARRAY_ELEM(map->members, ip_set_ip_t *, i);
++ elem = HARRAY_ELEM(map->members, ip_set_ip_t *, i);
+ if (*elem)
+ res = __addip_base(tmp, *elem);
+ }
+ kfree(tmp);
+ goto again;
+ }
-+
++
+ /* Success at resizing! */
+ members = map->members;
-+
++
+ map->hashsize = tmp->hashsize;
+ map->members = tmp->members;
+ write_unlock_bh(&set->lock);
+
+ if (!ip)
+ return -ERANGE;
-+
++
+ id = hash_id_cidr(map, ip, cidr, hash_ip);
+ if (id == UINT_MAX)
+ return -EEXIST;
-+
++
+ elem = HARRAY_ELEM(map->members, ip_set_ip_t *, id);
+ *elem = 0;
+ map->elements--;
+ size);
+ return -EINVAL;
+ }
-+ /* TODO: no garbage collection in map->cidr */
-+ return __delip((struct ip_set_nethash *) set->data,
++ /* TODO: no garbage collection in map->cidr */
++ return __delip((struct ip_set_nethash *) set->data,
+ req->ip, req->cidr, hash_ip);
+}
+
+static int
-+delip_kernel(struct ip_set *set,
++delip_kernel(struct ip_set *set,
+ const struct sk_buff *skb,
+ ip_set_ip_t *hash_ip,
+ const u_int32_t *flags,
+{
+ struct ip_set_nethash *map = (struct ip_set_nethash *) set->data;
+ int ret = -ERANGE;
-+ ip_set_ip_t ip = ntohl(flags[index] & IPSET_SRC
++ ip_set_ip_t ip = ntohl(flags[index] & IPSET_SRC
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
-+ ? ip_hdr(skb)->saddr
++ ? ip_hdr(skb)->saddr
+ : ip_hdr(skb)->daddr);
+#else
+ ? skb->nh.iph->saddr
+ : skb->nh.iph->daddr);
+#endif
-+
++
+ if (map->cidr[0])
+ ret = __delip(map, ip, map->cidr[0], hash_ip);
-+
++
+ return ret;
+}
+
+ kfree(map);
+ return -ENOMEM;
+ }
-+
++
+ set->data = map;
+ return 0;
+}
+ ip_set_ip_t i, *elem;
+
+ for (i = 0; i < map->hashsize; i++) {
-+ elem = HARRAY_ELEM(map->members, ip_set_ip_t *, i);
++ elem = HARRAY_ELEM(map->members, ip_set_ip_t *, i);
+ ((ip_set_ip_t *)data)[i] = *elem;
+ }
+}
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
-+ * published by the Free Software Foundation.
++ * published by the Free Software Foundation.
+ */
+
+/* Kernel module implementing a port set type as a bitmap */
+ switch (iph->protocol) {
+ case IPPROTO_TCP: {
+ struct tcphdr tcph;
-+
++
+ /* See comments at tcp_match in ip_tables.c */
+ if (offset)
+ return INVALID_PORT;
+#endif
+ /* No choice either */
+ return INVALID_PORT;
-+
++
+ return ntohs(flags & IPSET_SRC ?
+ tcph.source : tcph.dest);
+ }
+#endif
+ /* No choice either */
+ return INVALID_PORT;
-+
++
+ return ntohs(flags & IPSET_SRC ?
+ udph.source : udph.dest);
+ }
+
+ if (port < map->first_port || port > map->last_port)
+ return -ERANGE;
-+
++
+ *hash_port = port;
+ DP("set: %s, port:%u, %u", set->name, port, *hash_port);
+ return !!test_bit(port - map->first_port, map->members);
+testport(struct ip_set *set, const void *data, size_t size,
+ ip_set_ip_t *hash_port)
+{
-+ struct ip_set_req_portmap *req =
++ struct ip_set_req_portmap *req =
+ (struct ip_set_req_portmap *) data;
+
+ if (size != sizeof(struct ip_set_req_portmap)) {
+}
+
+static int
-+testport_kernel(struct ip_set *set,
++testport_kernel(struct ip_set *set,
+ const struct sk_buff *skb,
+ ip_set_ip_t *hash_port,
+ const u_int32_t *flags,
+ int res;
+ ip_set_ip_t port = get_port(skb, flags[index]);
+
-+ DP("flag %s port %u", flags[index] & IPSET_SRC ? "SRC" : "DST", port);
++ DP("flag %s port %u", flags[index] & IPSET_SRC ? "SRC" : "DST", port);
+ if (port == INVALID_PORT)
-+ return 0;
++ return 0;
+
+ res = __testport(set, port, hash_port);
-+
++
+ return (res < 0 ? 0 : res);
+}
+
+ return -ERANGE;
+ if (test_and_set_bit(port - map->first_port, map->members))
+ return -EEXIST;
-+
++
+ *hash_port = port;
+ DP("port %u", port);
+ return 0;
+addport(struct ip_set *set, const void *data, size_t size,
+ ip_set_ip_t *hash_port)
+{
-+ struct ip_set_req_portmap *req =
++ struct ip_set_req_portmap *req =
+ (struct ip_set_req_portmap *) data;
+
+ if (size != sizeof(struct ip_set_req_portmap)) {
+}
+
+static int
-+addport_kernel(struct ip_set *set,
++addport_kernel(struct ip_set *set,
+ const struct sk_buff *skb,
+ ip_set_ip_t *hash_port,
+ const u_int32_t *flags,
+ unsigned char index)
+{
+ ip_set_ip_t port = get_port(skb, flags[index]);
-+
++
+ if (port == INVALID_PORT)
+ return -EINVAL;
+
+ return -ERANGE;
+ if (!test_and_clear_bit(port - map->first_port, map->members))
+ return -EEXIST;
-+
++
+ *hash_port = port;
+ DP("port %u", port);
+ return 0;
+}
+
+static int
-+delport_kernel(struct ip_set *set,
++delport_kernel(struct ip_set *set,
+ const struct sk_buff *skb,
+ ip_set_ip_t *hash_port,
+ const u_int32_t *flags,
+ unsigned char index)
+{
+ ip_set_ip_t port = get_port(skb, flags[index]);
-+
++
+ if (port == INVALID_PORT)
+ return -EINVAL;
+
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
-+ * published by the Free Software Foundation.
++ * published by the Free Software Foundation.
+ */
+
+/* Kernel module to match an IP set. */
+match_set(const struct ipt_set_info *info,
+ const struct sk_buff *skb,
+ int inv)
-+{
++{
+ if (ip_set_testip_kernel(info->index, skb, info->flags))
+ inv = !inv;
+ return inv;
+#endif
+{
+ const struct ipt_set_info_match *info = matchinfo;
-+
++
+ return match_set(&info->match_set,
+ skb,
+ info->match_set.flags[0] & IPSET_MATCH_INV);
+#endif
+ unsigned int hook_mask)
+{
-+ struct ipt_set_info_match *info =
++ struct ipt_set_info_match *info =
+ (struct ipt_set_info_match *) matchinfo;
+ ip_set_id_t index;
+
+#endif
+
+ index = ip_set_get_byindex(info->match_set.index);
-+
++
+ if (index == IP_SET_INVALID_ID) {
+ ip_set_printk("Cannot find set indentified by id %u to match",
+ info->match_set.index);
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
-+ * published by the Free Software Foundation.
++ * published by the Free Software Foundation.
+ */
+
+/* ipt_SET.c - netfilter target to manipulate IP sets */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
+ struct sk_buff *skb = *pskb;
+#endif
-+
++
+ if (info->add_set.index != IP_SET_INVALID_ID)
+ ip_set_addip_kernel(info->add_set.index,
+ skb,
+#endif
+ void *targinfo,
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
-+ unsigned int targinfosize,
++ unsigned int targinfosize,
+#endif
+ unsigned int hook_mask)
+{
-+ struct ipt_set_info_target *info =
++ struct ipt_set_info_target *info =
+ (struct ipt_set_info_target *) targinfo;
+ ip_set_id_t index;
+
+module_exit(ipt_SET_fini);
--- a/net/ipv4/netfilter/Kconfig
+++ b/net/ipv4/netfilter/Kconfig
-@@ -385,5 +385,122 @@
+@@ -401,5 +401,122 @@ config IP_NF_ARP_MANGLE
Allows altering the ARP packet payload: source and destination
hardware and network addresses.
--- a/net/ipv4/netfilter/Makefile
+++ b/net/ipv4/netfilter/Makefile
-@@ -46,6 +46,7 @@
+@@ -49,6 +49,7 @@ obj-$(CONFIG_IP_NF_MATCH_AH) += ipt_ah.o
obj-$(CONFIG_IP_NF_MATCH_ECN) += ipt_ecn.o
obj-$(CONFIG_IP_NF_MATCH_RECENT) += ipt_recent.o
obj-$(CONFIG_IP_NF_MATCH_TTL) += ipt_ttl.o
obj-$(CONFIG_IP_NF_MATCH_IPP2P) += ipt_ipp2p.o
-@@ -59,6 +60,18 @@
+@@ -62,6 +63,18 @@ obj-$(CONFIG_IP_NF_TARGET_REDIRECT) += i
obj-$(CONFIG_IP_NF_TARGET_REJECT) += ipt_REJECT.o
obj-$(CONFIG_IP_NF_TARGET_TTL) += ipt_TTL.o
obj-$(CONFIG_IP_NF_TARGET_ULOG) += ipt_ULOG.o