]> git.ipfire.org Git - thirdparty/xtables-addons.git/commitdiff
ipset: update to 6.0
authorJan Engelhardt <jengelh@medozas.de>
Wed, 23 Feb 2011 23:40:23 +0000 (00:40 +0100)
committerJan Engelhardt <jengelh@medozas.de>
Wed, 23 Feb 2011 23:40:23 +0000 (00:40 +0100)
30 files changed:
doc/changelog.txt
extensions/ipset-6/README [new file with mode: 0644]
extensions/ipset-6/include/libipset/linux_ip_set.h
extensions/ipset-6/include/libipset/parse.h
extensions/ipset-6/include/libipset/types.h
extensions/ipset-6/ip_set.h
extensions/ipset-6/ip_set_ahash.h
extensions/ipset-6/ip_set_bitmap_ip.c
extensions/ipset-6/ip_set_bitmap_ipmac.c
extensions/ipset-6/ip_set_bitmap_port.c
extensions/ipset-6/ip_set_core.c
extensions/ipset-6/ip_set_getport.c
extensions/ipset-6/ip_set_getport.h
extensions/ipset-6/ip_set_hash_ip.c
extensions/ipset-6/ip_set_hash_ipport.c
extensions/ipset-6/ip_set_hash_ipportip.c
extensions/ipset-6/ip_set_hash_ipportnet.c
extensions/ipset-6/ip_set_hash_net.c
extensions/ipset-6/ip_set_hash_netport.c
extensions/ipset-6/ip_set_list_set.c
extensions/ipset-6/libipset/mnl.c
extensions/ipset-6/libipset/parse.c
extensions/ipset-6/libipset/print.c
extensions/ipset-6/libipset/types.c
extensions/ipset-6/src/errcode.c
extensions/ipset-6/src/ipset.c
extensions/ipset-6/src/ui.c
extensions/ipset-6/xt_set.c
extensions/ipset-6/xt_set.h
mconfig

index 3a21fb4b6c930238096ebb2173e7b67c666d533c..922054b0c644a5daa224591d6958eea881c6a80c 100644 (file)
@@ -1,6 +1,20 @@
 
 HEAD
 ====
+Enhancements:
+- update to ipset 6.0
+  * allow "new" as a commad alias to "create"
+  * ipset: improve command argument parsing
+  * ipset: avoid the unnecessary argv[] loop
+  * ipset: pass ipset_arg argument pointer
+  * separate ipset errnos completely from system ones and bump protocol version
+  * resolving IP addresses did not work at listing/saving sets, fixed
+  * ipset: fix spelling error
+  * ipset: fix the Netlink sequence number
+  * ipset: turn Set name[] into a const pointer
+  * check ICMP and ICMPv6 with the set match and target in the testsuite
+  * avoid possible syntax clashing at saving hostnames
+  * fix linking with CONFIG_IPV6=n
 
 
 v1.33 (2011-02-02)
diff --git a/extensions/ipset-6/README b/extensions/ipset-6/README
new file mode 100644 (file)
index 0000000..a7ef16c
--- /dev/null
@@ -0,0 +1,88 @@
+This is the ipset source tree. Follow the next steps to install ipset.
+If you upgrade from an earlier 5.x release, please read the UPGRADE
+instructions too.
+
+0. You need the source tree of your kernel (version >= 2.6.34)
+   and it have to be configured with ip6tables support enabled,
+   modules compiled. Please apply the netlink.patch against your kernel
+   tree, which adds the new subsystem identifier for ipset.
+
+   Recompile and install the patched kernel and its modules. Please note,
+   you have to run the patched kernel for ipset to work.
+
+   The ipset source code depends on the libmnl library so the library
+   must be installed. You can download the libmnl library from
+
+       git://git.netfilter.org/libmnl.git
+
+1. Initialize the compiling environment for ipset. The packages automake,
+   autoconf and libtool are required.
+
+   % ./autogen.sh
+
+2. Run `./configure` and then compile the ipset binary and the kernel
+   modules.
+
+   Configure parameters can be used to to override the default path
+   to the kernel source tree (/lib/modules/`uname -r`/build),
+   the maximum number of sets (256), the default hash sizes (1024).
+   See `./configure --help`.
+
+   % ./configure
+   % make
+   % make modules
+
+3. Install the binary and the kernel modules
+
+   # make install
+   # make modules_install
+
+   After installing the modules, you can run the testsuite as well.
+   Please note, several assumptions must be met for the testsuite:
+
+       - no sets defined
+       - iptables/ip6tables rules are not set up
+       - the destination for kernel logs is /var/log/kern.log
+       - the networks 10.255.255.0/24 and 1002:1002:1002:1002::/64
+         are not in use
+       - sendip utility is installed
+
+   # make tests
+
+4. Cleanup the source tree
+
+   % make clean
+   % make modules_clean
+
+That's it! 
+
+Read the ipset(8) and iptables(8), ip6tables(8) manpages on how to use
+ipset and its match and target from iptables.
+
+Compatibilities and incompatibilities:
+
+- The ipset 6.x userspace utility contains a backward compatibility
+  interface to support the commandline syntax of ipset 4.x.
+  The commandline syntax of ipset 6.x is fully compatible with 5.x.
+- The ipset 6.x userspace utility can't talk to the kernel part of ipset 5.x
+  or 4.x.
+- The ipset 6.x kernel part can't talk to the userspace utility from
+  ipset 5.x or 4.x.
+- The ipset 6.x kernel part can work together with the set match and SET
+  target from iptables 1.4.7 and below, however if you need the IPv6 support
+  from ipset 6.x, then you have to use iptables 1.4.8 or above.
+
+The ipset 6.x can interpret the commandline syntax of ipset 4.x, however
+some internal changes mean different behaviour:
+
+- The "--matchunset" flag for the macipmap type is ignored and not used
+  anymore.
+- The "--probes" and "--resize" parameters of the hash types are ignored
+  and not used anymore.
+- The "--from", "--to" and "--network" parameters of the ipporthash,
+  ipportiphash and ipportnethash types are ignored and not used anymore.
+- The hash types are not resized when new entries are added by the SET
+  target. If you use a set together with the SET target, create it with
+  the proper size because it won't be resized automatically.
+- The iptree, iptreemap types are not implemented in ipset 6.x. The types
+  are automatically substituted with the hash:ip type.
index 1fb7ea23219389808d80e52c7d94e69e18569892..d4b6308b82e2d185987657e3aa0feb0f6be2e8ec 100644 (file)
@@ -4,7 +4,7 @@
 /* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu>
  *                         Patrick Schaaf <bof@bof.de>
  *                         Martin Josefsson <gandalf@wlug.westbo.se>
- * Copyright (C) 2003-2010 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
+ * Copyright (C) 2003-2011 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
  *
  * 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
@@ -12,7 +12,7 @@
  */
 
 /* The protocol version */
-#define IPSET_PROTOCOL         5
+#define IPSET_PROTOCOL         60
 
 /* The max length of strings including NUL: set and type identifiers */
 #define IPSET_MAXNAMELEN       32
@@ -118,7 +118,7 @@ enum {
 
 /* Error codes */
 enum ipset_errno {
-       IPSET_ERR_PRIVATE = 128,
+       IPSET_ERR_PRIVATE = 4096,
        IPSET_ERR_PROTOCOL,
        IPSET_ERR_FIND_TYPE,
        IPSET_ERR_MAX_SETS,
@@ -135,7 +135,7 @@ enum ipset_errno {
        IPSET_ERR_IPADDR_IPV6,
 
        /* Type specific error codes */
-       IPSET_ERR_TYPE_SPECIFIC = 160,
+       IPSET_ERR_TYPE_SPECIFIC = 4352,
 };
 
 /* Flags at command level */
index e87a60d87144201ecea23cb5eb767af5bb1e5ef6..760df49abce5cbf864a8928dffadfd9e39271851 100644 (file)
@@ -17,6 +17,7 @@
 #define IPSET_PROTO_SEPARATOR  ":"
 
 struct ipset_session;
+struct ipset_arg;
 
 typedef int (*ipset_parsefn)(struct ipset_session *s,
                             enum ipset_opt opt, const char *str);
@@ -84,8 +85,8 @@ extern int ipset_parse_ignored(struct ipset_session *session,
 extern int ipset_parse_elem(struct ipset_session *session,
                             enum ipset_opt opt, const char *str);
 extern int ipset_call_parser(struct ipset_session *session,
-                            ipset_parsefn parse, const char *optstr,
-                            enum ipset_opt optional, const char *str);
+                                                        const struct ipset_arg *arg,
+                                                        const char *str);
 
 /* Compatibility parser functions */
 extern int ipset_parse_iptimeout(struct ipset_session *session,
index f9c8f2d6c676abe7b58d680e29f294db2e5459a4..d8973db00905848644547a33f66c98ea9dd0a0ea 100644 (file)
@@ -70,7 +70,7 @@ struct ipset_elem {
  * but for the readability the full list is supported.
   */
 struct ipset_type {
-       char name[IPSET_MAXNAMELEN];            /* type name */
+       const char *name;
        uint8_t revision;                       /* revision number */
        uint8_t family;                         /* supported family */
        uint8_t dimension;                      /* elem dimension */
index 9d4b9614cc940fca49bcf4ba3aaa8326311efb1f..ec1438f3229d2b07d6ac9aefd02fc131b5693248 100644 (file)
@@ -14,7 +14,7 @@
 #include <linux/netlink.h>
 
 /* The protocol version */
-#define IPSET_PROTOCOL         5
+#define IPSET_PROTOCOL         60
 
 /* The max length of strings including NUL: set and type identifiers */
 #define IPSET_MAXNAMELEN       32
@@ -120,7 +120,7 @@ enum {
 
 /* Error codes */
 enum ipset_errno {
-       IPSET_ERR_PRIVATE = 128,
+       IPSET_ERR_PRIVATE = 4096,
        IPSET_ERR_PROTOCOL,
        IPSET_ERR_FIND_TYPE,
        IPSET_ERR_MAX_SETS,
@@ -137,7 +137,7 @@ enum ipset_errno {
        IPSET_ERR_IPADDR_IPV6,
 
        /* Type specific error codes */
-       IPSET_ERR_TYPE_SPECIFIC = 160,
+       IPSET_ERR_TYPE_SPECIFIC = 4352,
 };
 
 /* Flags at command level */
@@ -231,7 +231,7 @@ struct ip_set_type_variant {
         *              returns negative error code,
         *                      zero for no match/success to add/delete
         *                      positive for matching element */
-       int (*uadt)(struct ip_set *set, struct nlattr *head, int len,
+       int (*uadt)(struct ip_set *set, struct nlattr *tb[],
                    enum ipset_adt adt, u32 *lineno, u32 flags);
 
        /* Low level add/del/test functions */
@@ -274,8 +274,11 @@ struct ip_set_type {
        u8 revision;
 
        /* Create set */
-       int (*create)(struct ip_set *set,
-                     struct nlattr *head, int len, u32 flags);
+       int (*create)(struct ip_set *set, struct nlattr *tb[], u32 flags);
+
+       /* Attribute policies */
+       const struct nla_policy create_policy[IPSET_ATTR_CREATE_MAX + 1];
+       const struct nla_policy adt_policy[IPSET_ATTR_ADT_MAX + 1];
 
        /* Set this to THIS_MODULE if you are a module, otherwise NULL */
        struct module *me;
@@ -320,7 +323,7 @@ extern int ip_set_test(ip_set_id_t id, const struct sk_buff *skb,
                       u8 family, u8 dim, u8 flags);
 
 /* Utility functions */
-extern void * ip_set_alloc(size_t size, gfp_t gfp_mask);
+extern void * ip_set_alloc(size_t size);
 extern void ip_set_free(void *members);
 extern int ip_set_get_ipaddr4(struct nlattr *nla,  __be32 *ipaddr);
 extern int ip_set_get_ipaddr6(struct nlattr *nla, union nf_inet_addr *ipaddr);
index 2f4bb3affb388a8691762ee0b6c71df54f9f1ab3..b6c4c2fcef804033eafb37eafbc51e05a4d44975 100644 (file)
@@ -311,8 +311,7 @@ retry:
                /* In case we have plenty of memory :-) */
                return -IPSET_ERR_HASH_FULL;
        t = ip_set_alloc(sizeof(*t)
-                        + jhash_size(htable_bits) * sizeof(struct hbucket),
-                        GFP_KERNEL);
+                        + jhash_size(htable_bits) * sizeof(struct hbucket));
        if (!t)
                return -ENOMEM;
        t->htable_bits = htable_bits;
@@ -525,7 +524,7 @@ type_pf_head(struct ip_set *set, struct sk_buff *skb)
 
        return 0;
 nla_put_failure:
-       return -EFAULT;
+       return -EMSGSIZE;
 }
 
 /* Reply a LIST/SAVE request: dump the elements of the specified set */
@@ -545,7 +544,7 @@ type_pf_list(const struct ip_set *set,
 
        atd = ipset_nest_start(skb, IPSET_ATTR_ADT);
        if (!atd)
-               return -EFAULT;
+               return -EMSGSIZE;
        pr_debug("list hash set %s\n", set->name);
        for (; cb->args[2] < jhash_size(t->htable_bits); cb->args[2]++) {
                incomplete = skb_tail_pointer(skb);
@@ -559,7 +558,7 @@ type_pf_list(const struct ip_set *set,
                        if (!nested) {
                                if (cb->args[2] == first) {
                                        nla_nest_cancel(skb, atd);
-                                       return -EFAULT;
+                                       return -EMSGSIZE;
                                } else
                                        goto nla_put_failure;
                        }
@@ -581,6 +580,7 @@ nla_put_failure:
                pr_warning("Can't list set %s: one bucket does not fit into "
                           "a message. Please report it!\n", set->name);
                cb->args[2] = 0;
+               return -EMSGSIZE;
        }
        return 0;
 }
@@ -589,7 +589,7 @@ static int
 type_pf_kadt(struct ip_set *set, const struct sk_buff * skb,
             enum ipset_adt adt, u8 pf, u8 dim, u8 flags);
 static int
-type_pf_uadt(struct ip_set *set, struct nlattr *head, int len,
+type_pf_uadt(struct ip_set *set, struct nlattr *tb[],
             enum ipset_adt adt, u32 *lineno, u32 flags);
 
 static const struct ip_set_type_variant type_pf_variant = {
@@ -742,8 +742,7 @@ retry:
                /* In case we have plenty of memory :-) */
                return -IPSET_ERR_HASH_FULL;
        t = ip_set_alloc(sizeof(*t)
-                        + jhash_size(htable_bits) * sizeof(struct hbucket),
-                        GFP_KERNEL);
+                        + jhash_size(htable_bits) * sizeof(struct hbucket));
        if (!t)
                return -ENOMEM;
        t->htable_bits = htable_bits;
@@ -946,7 +945,7 @@ type_pf_tlist(const struct ip_set *set,
 
        atd = ipset_nest_start(skb, IPSET_ATTR_ADT);
        if (!atd)
-               return -EFAULT;
+               return -EMSGSIZE;
        for (; cb->args[2] < jhash_size(t->htable_bits); cb->args[2]++) {
                incomplete = skb_tail_pointer(skb);
                n = hbucket(t, cb->args[2]);
@@ -960,7 +959,7 @@ type_pf_tlist(const struct ip_set *set,
                        if (!nested) {
                                if (cb->args[2] == first) {
                                        nla_nest_cancel(skb, atd);
-                                       return -EFAULT;
+                                       return -EMSGSIZE;
                                } else
                                        goto nla_put_failure;
                        }
@@ -982,6 +981,7 @@ nla_put_failure:
                pr_warning("Can't list set %s: one bucket does not fit into "
                           "a message. Please report it!\n", set->name);
                cb->args[2] = 0;
+               return -EMSGSIZE;
        }
        return 0;
 }
index e0118649dea4de805d0d9910da5cdcade7122539..41cfded02f5b5161b07c2cadd9e9d60a951352e2 100644 (file)
@@ -13,7 +13,6 @@
 #include <linux/ip.h>
 #include <linux/skbuff.h>
 #include <linux/errno.h>
-#include <linux/uaccess.h>
 #include <linux/bitops.h>
 #include <linux/spinlock.h>
 #include <linux/netlink.h>
@@ -33,8 +32,7 @@ MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
 MODULE_DESCRIPTION("bitmap:ip type of IP sets");
 MODULE_ALIAS("ip_set_bitmap:ip");
 
-/* Base variant */
-
+/* Type structure */
 struct bitmap_ip {
        void *members;          /* the set members */
        u32 first_ip;           /* host byte order, included in range */
@@ -43,181 +41,49 @@ struct bitmap_ip {
        u32 hosts;              /* number of hosts in a subnet */
        size_t memsize;         /* members size */
        u8 netmask;             /* subnet netmask */
+       u32 timeout;            /* timeout parameter */
+       struct timer_list gc;   /* garbage collection */
 };
 
+/* Base variant */
+
 static inline u32
 ip_to_id(const struct bitmap_ip *m, u32 ip)
 {
        return ((ip & ip_set_hostmask(m->netmask)) - m->first_ip)/m->hosts;
 }
 
-static inline int
-bitmap_ip_test(const struct bitmap_ip *map, u32 id)
-{
-       return !!test_bit(id, map->members);
-}
-
-static inline int
-bitmap_ip_add(struct bitmap_ip *map, u32 id)
-{
-       if (test_and_set_bit(id, map->members))
-               return -IPSET_ERR_EXIST;
-
-       return 0;
-}
-
-static inline int
-bitmap_ip_del(struct bitmap_ip *map, u32 id)
-{
-       if (!test_and_clear_bit(id, map->members))
-               return -IPSET_ERR_EXIST;
-
-       return 0;
-}
-
 static int
-bitmap_ip_kadt(struct ip_set *set, const struct sk_buff *skb,
-              enum ipset_adt adt, u8 pf, u8 dim, u8 flags)
+bitmap_ip_test(struct ip_set *set, void *value, u32 timeout)
 {
-       struct bitmap_ip *map = set->data;
-       u32 ip;
-
-       ip = ntohl(ip4addr(skb, flags & IPSET_DIM_ONE_SRC));
-       if (ip < map->first_ip || ip > map->last_ip)
-               return -IPSET_ERR_BITMAP_RANGE;
-
-       ip = ip_to_id(map, ip);
+       const struct bitmap_ip *map = set->data;
+       u16 id = *(u16 *)value;
 
-       switch (adt) {
-       case IPSET_TEST:
-               return bitmap_ip_test(map, ip);
-       case IPSET_ADD:
-               return bitmap_ip_add(map, ip);
-       case IPSET_DEL:
-               return bitmap_ip_del(map, ip);
-       default:
-               return -EINVAL;
-       }
+       return !!test_bit(id, map->members);
 }
 
-static const struct nla_policy bitmap_ip_adt_policy[IPSET_ATTR_ADT_MAX+1] = {
-       [IPSET_ATTR_IP]         = { .type = NLA_NESTED },
-       [IPSET_ATTR_IP_TO]      = { .type = NLA_NESTED },
-       [IPSET_ATTR_CIDR]       = { .type = NLA_U8 },
-       [IPSET_ATTR_TIMEOUT]    = { .type = NLA_U32 },
-       [IPSET_ATTR_LINENO]     = { .type = NLA_U32 },
-};
-
 static int
-bitmap_ip_uadt(struct ip_set *set, struct nlattr *head, int len,
-              enum ipset_adt adt, u32 *lineno, u32 flags)
+bitmap_ip_add(struct ip_set *set, void *value, u32 timeout)
 {
        struct bitmap_ip *map = set->data;
-       struct nlattr *tb[IPSET_ATTR_ADT_MAX+1];
-       u32 ip, ip_to, id;
-       int ret = 0;
-
-       if (nla_parse(tb, IPSET_ATTR_ADT_MAX, head, len,
-                     bitmap_ip_adt_policy))
-               return -IPSET_ERR_PROTOCOL;
-
-       if (unlikely(!tb[IPSET_ATTR_IP]))
-               return -IPSET_ERR_PROTOCOL;
-
-       if (tb[IPSET_ATTR_LINENO])
-               *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
-
-       ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP], &ip);
-       if (ret)
-               return ret;
-
-       if (ip < map->first_ip || ip > map->last_ip)
-               return -IPSET_ERR_BITMAP_RANGE;
-
-       /* Set was defined without timeout support:
-        * don't ignore the attribute silently */
-       if (tb[IPSET_ATTR_TIMEOUT])
-               return -IPSET_ERR_TIMEOUT;
+       u16 id = *(u16 *)value;
 
-       if (adt == IPSET_TEST)
-               return bitmap_ip_test(map, ip_to_id(map, ip));
-
-       if (tb[IPSET_ATTR_IP_TO]) {
-               ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP_TO], &ip_to);
-               if (ret)
-                       return ret;
-               if (ip > ip_to) {
-                       swap(ip, ip_to);
-                       if (ip < map->first_ip)
-                               return -IPSET_ERR_BITMAP_RANGE;
-               }
-       } else if (tb[IPSET_ATTR_CIDR]) {
-               u8 cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
-
-               if (cidr > 32)
-                       return -IPSET_ERR_INVALID_CIDR;
-               ip &= ip_set_hostmask(cidr);
-               ip_to = ip | ~ip_set_hostmask(cidr);
-       } else
-               ip_to = ip;
-
-       if (ip_to > map->last_ip)
-               return -IPSET_ERR_BITMAP_RANGE;
-
-       for (; !before(ip_to, ip); ip += map->hosts) {
-               id = ip_to_id(map, ip);
-               ret = adt == IPSET_ADD ? bitmap_ip_add(map, id)
-                                      : bitmap_ip_del(map, id);
-
-               if (ret && !ip_set_eexist(ret, flags))
-                       return ret;
-               else
-                       ret = 0;
-       }
-       return ret;
-}
-
-static void
-bitmap_ip_destroy(struct ip_set *set)
-{
-       struct bitmap_ip *map = set->data;
-
-       ip_set_free(map->members);
-       kfree(map);
-
-       set->data = NULL;
-}
-
-static void
-bitmap_ip_flush(struct ip_set *set)
-{
-       struct bitmap_ip *map = set->data;
+       if (test_and_set_bit(id, map->members))
+               return -IPSET_ERR_EXIST;
 
-       memset(map->members, 0, map->memsize);
+       return 0;
 }
 
 static int
-bitmap_ip_head(struct ip_set *set, struct sk_buff *skb)
+bitmap_ip_del(struct ip_set *set, void *value, u32 timeout)
 {
-       const struct bitmap_ip *map = set->data;
-       struct nlattr *nested;
+       struct bitmap_ip *map = set->data;
+       u16 id = *(u16 *)value;
 
-       nested = ipset_nest_start(skb, IPSET_ATTR_DATA);
-       if (!nested)
-               goto nla_put_failure;
-       NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, htonl(map->first_ip));
-       NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP_TO, htonl(map->last_ip));
-       if (map->netmask != 32)
-               NLA_PUT_U8(skb, IPSET_ATTR_NETMASK, map->netmask);
-       NLA_PUT_NET32(skb, IPSET_ATTR_REFERENCES,
-                     htonl(atomic_read(&set->ref) - 1));
-       NLA_PUT_NET32(skb, IPSET_ATTR_MEMSIZE,
-                     htonl(sizeof(*map) + map->memsize));
-       ipset_nest_end(skb, nested);
+       if (!test_and_clear_bit(id, map->members))
+               return -IPSET_ERR_EXIST;
 
        return 0;
-nla_put_failure:
-       return -EFAULT;
 }
 
 static int
@@ -230,16 +96,16 @@ bitmap_ip_list(const struct ip_set *set,
 
        atd = ipset_nest_start(skb, IPSET_ATTR_ADT);
        if (!atd)
-               return -EFAULT;
+               return -EMSGSIZE;
        for (; cb->args[2] < map->elements; cb->args[2]++) {
                id = cb->args[2];
-               if (!bitmap_ip_test(map, id))
+               if (!test_bit(id, map->members))
                        continue;
                nested = ipset_nest_start(skb, IPSET_ATTR_DATA);
                if (!nested) {
                        if (id == first) {
                                nla_nest_cancel(skb, atd);
-                               return -EFAULT;
+                               return -EMSGSIZE;
                        } else
                                goto nla_put_failure;
                }
@@ -255,113 +121,129 @@ bitmap_ip_list(const struct ip_set *set,
 nla_put_failure:
        nla_nest_cancel(skb, nested);
        ipset_nest_end(skb, atd);
+       if (unlikely(id == first)) {
+               cb->args[2] = 0;
+               return -EMSGSIZE;
+       }
        return 0;
 }
 
-static bool
-bitmap_ip_same_set(const struct ip_set *a, const struct ip_set *b)
-{
-       const struct bitmap_ip *x = a->data;
-       const struct bitmap_ip *y = b->data;
-
-       return x->first_ip == y->first_ip &&
-              x->last_ip == y->last_ip &&
-              x->netmask == y->netmask;
-}
-
-static const struct ip_set_type_variant bitmap_ip = {
-       .kadt   = bitmap_ip_kadt,
-       .uadt   = bitmap_ip_uadt,
-       .destroy = bitmap_ip_destroy,
-       .flush  = bitmap_ip_flush,
-       .head   = bitmap_ip_head,
-       .list   = bitmap_ip_list,
-       .same_set = bitmap_ip_same_set,
-};
-
 /* Timeout variant */
 
-struct bitmap_ip_timeout {
-       unsigned long *members; /* the set members */
-       u32 first_ip;           /* host byte order, included in range */
-       u32 last_ip;            /* host byte order, included in range */
-       u32 elements;           /* number of max elements in the set */
-       u32 hosts;              /* number of hosts in a subnet */
-       size_t memsize;         /* members size */
-       u8 netmask;             /* subnet netmask */
-
-       u32 timeout;            /* timeout parameter */
-       struct timer_list gc;   /* garbage collection */
-};
-
-static inline bool
-bitmap_ip_timeout_test(const struct bitmap_ip_timeout *map, u32 id)
+static int
+bitmap_ip_ttest(struct ip_set *set, void *value, u32 timeout)
 {
-       return ip_set_timeout_test(map->members[id]);
+       const struct bitmap_ip *map = set->data;
+       const unsigned long *members = map->members;
+       u16 id = *(u16 *)value;
+
+       return ip_set_timeout_test(members[id]);
 }
 
-static inline int
-bitmap_ip_timeout_add(struct bitmap_ip_timeout *map,
-                     u32 id, u32 timeout)
+static int
+bitmap_ip_tadd(struct ip_set *set, void *value, u32 timeout)
 {
-       if (bitmap_ip_timeout_test(map, id))
+       struct bitmap_ip *map = set->data;
+       unsigned long *members = map->members;
+       u16 id = *(u16 *)value;
+
+       if (ip_set_timeout_test(members[id]))
                return -IPSET_ERR_EXIST;
 
-       map->members[id] = ip_set_timeout_set(timeout);
+       members[id] = ip_set_timeout_set(timeout);
 
        return 0;
 }
 
-static inline int
-bitmap_ip_timeout_del(struct bitmap_ip_timeout *map, u32 id)
+static int
+bitmap_ip_tdel(struct ip_set *set, void *value, u32 timeout)
 {
+       struct bitmap_ip *map = set->data;
+       unsigned long *members = map->members;
+       u16 id = *(u16 *)value;
        int ret = -IPSET_ERR_EXIST;
 
-       if (bitmap_ip_timeout_test(map, id))
+       if (ip_set_timeout_test(members[id]))
                ret = 0;
 
-       map->members[id] = IPSET_ELEM_UNSET;
+       members[id] = IPSET_ELEM_UNSET;
        return ret;
 }
 
 static int
-bitmap_ip_timeout_kadt(struct ip_set *set, const struct sk_buff *skb,
-                      enum ipset_adt adt, u8 pf, u8 dim, u8 flags)
+bitmap_ip_tlist(const struct ip_set *set,
+               struct sk_buff *skb, struct netlink_callback *cb)
 {
-       struct bitmap_ip_timeout *map = set->data;
+       const struct bitmap_ip *map = set->data;
+       struct nlattr *adt, *nested;
+       u32 id, first = cb->args[2];
+       const unsigned long *members = map->members;
+
+       adt = ipset_nest_start(skb, IPSET_ATTR_ADT);
+       if (!adt)
+               return -EMSGSIZE;
+       for (; cb->args[2] < map->elements; cb->args[2]++) {
+               id = cb->args[2];
+               if (!ip_set_timeout_test(members[id]))
+                       continue;
+               nested = ipset_nest_start(skb, IPSET_ATTR_DATA);
+               if (!nested) {
+                       if (id == first) {
+                               nla_nest_cancel(skb, adt);
+                               return -EMSGSIZE;
+                       } else
+                               goto nla_put_failure;
+               }
+               NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP,
+                               htonl(map->first_ip + id * map->hosts));
+               NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT,
+                             htonl(ip_set_timeout_get(members[id])));
+               ipset_nest_end(skb, nested);
+       }
+       ipset_nest_end(skb, adt);
+
+       /* Set listing finished */
+       cb->args[2] = 0;
+
+       return 0;
+
+nla_put_failure:
+       nla_nest_cancel(skb, nested);
+       ipset_nest_end(skb, adt);
+       if (unlikely(id == first)) {
+               cb->args[2] = 0;
+               return -EMSGSIZE;
+       }
+       return 0;
+}
+
+static int
+bitmap_ip_kadt(struct ip_set *set, const struct sk_buff *skb,
+              enum ipset_adt adt, u8 pf, u8 dim, u8 flags)
+{
+       struct bitmap_ip *map = set->data;
+       ipset_adtfn adtfn = set->variant->adt[adt];
        u32 ip;
 
        ip = ntohl(ip4addr(skb, flags & IPSET_DIM_ONE_SRC));
        if (ip < map->first_ip || ip > map->last_ip)
                return -IPSET_ERR_BITMAP_RANGE;
 
-       ip = ip_to_id((const struct bitmap_ip *)map, ip);
-
-       switch (adt) {
-       case IPSET_TEST:
-               return bitmap_ip_timeout_test(map, ip);
-       case IPSET_ADD:
-               return bitmap_ip_timeout_add(map, ip, map->timeout);
-       case IPSET_DEL:
-               return bitmap_ip_timeout_del(map, ip);
-       default:
-               return -EINVAL;
-       }
+       ip = ip_to_id(map, ip);
+
+       return adtfn(set, &ip, map->timeout);
 }
 
 static int
-bitmap_ip_timeout_uadt(struct ip_set *set, struct nlattr *head, int len,
-                      enum ipset_adt adt, u32 *lineno, u32 flags)
+bitmap_ip_uadt(struct ip_set *set, struct nlattr *tb[],
+              enum ipset_adt adt, u32 *lineno, u32 flags)
 {
-       struct bitmap_ip_timeout *map = set->data;
-       struct nlattr *tb[IPSET_ATTR_ADT_MAX+1];
-       u32 ip, ip_to, id, timeout = map->timeout;
+       struct bitmap_ip *map = set->data;
+       ipset_adtfn adtfn = set->variant->adt[adt];
+       u32 timeout = map->timeout;
+       u32 ip, ip_to, id;
        int ret = 0;
 
-       if (nla_parse(tb, IPSET_ATTR_ADT_MAX, head, len,
-                     bitmap_ip_adt_policy))
-               return -IPSET_ERR_PROTOCOL;
-
        if (unlikely(!tb[IPSET_ATTR_IP] ||
                     !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
                return -IPSET_ERR_PROTOCOL;
@@ -376,9 +258,16 @@ bitmap_ip_timeout_uadt(struct ip_set *set, struct nlattr *head, int len,
        if (ip < map->first_ip || ip > map->last_ip)
                return -IPSET_ERR_BITMAP_RANGE;
 
-       if (adt == IPSET_TEST)
-               return bitmap_ip_timeout_test(map,
-                               ip_to_id((const struct bitmap_ip *)map, ip));
+       if (tb[IPSET_ATTR_TIMEOUT]) {
+               if (!with_timeout(map->timeout))
+                       return -IPSET_ERR_TIMEOUT;
+               timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
+       }
+
+       if (adt == IPSET_TEST) {
+               id = ip_to_id(map, ip);
+               return adtfn(set, &id, timeout);
+       }
 
        if (tb[IPSET_ATTR_IP_TO]) {
                ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP_TO], &ip_to);
@@ -402,14 +291,9 @@ bitmap_ip_timeout_uadt(struct ip_set *set, struct nlattr *head, int len,
        if (ip_to > map->last_ip)
                return -IPSET_ERR_BITMAP_RANGE;
 
-       if (tb[IPSET_ATTR_TIMEOUT])
-               timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
-
        for (; !before(ip_to, ip); ip += map->hosts) {
-               id = ip_to_id((const struct bitmap_ip *)map, ip);
-               ret = adt == IPSET_ADD
-                       ? bitmap_ip_timeout_add(map, id, timeout)
-                       : bitmap_ip_timeout_del(map, id);
+               id = ip_to_id(map, ip);
+               ret = adtfn(set, &id, timeout);;
 
                if (ret && !ip_set_eexist(ret, flags))
                        return ret;
@@ -420,11 +304,13 @@ bitmap_ip_timeout_uadt(struct ip_set *set, struct nlattr *head, int len,
 }
 
 static void
-bitmap_ip_timeout_destroy(struct ip_set *set)
+bitmap_ip_destroy(struct ip_set *set)
 {
-       struct bitmap_ip_timeout *map = set->data;
+       struct bitmap_ip *map = set->data;
+
+       if (with_timeout(map->timeout))
+               del_timer_sync(&map->gc);
 
-       del_timer_sync(&map->gc);
        ip_set_free(map->members);
        kfree(map);
 
@@ -432,17 +318,17 @@ bitmap_ip_timeout_destroy(struct ip_set *set)
 }
 
 static void
-bitmap_ip_timeout_flush(struct ip_set *set)
+bitmap_ip_flush(struct ip_set *set)
 {
-       struct bitmap_ip_timeout *map = set->data;
+       struct bitmap_ip *map = set->data;
 
-       memset(map->members, IPSET_ELEM_UNSET, map->memsize);
+       memset(map->members, 0, map->memsize);
 }
 
 static int
-bitmap_ip_timeout_head(struct ip_set *set, struct sk_buff *skb)
+bitmap_ip_head(struct ip_set *set, struct sk_buff *skb)
 {
-       const struct bitmap_ip_timeout *map = set->data;
+       const struct bitmap_ip *map = set->data;
        struct nlattr *nested;
 
        nested = ipset_nest_start(skb, IPSET_ATTR_DATA);
@@ -452,66 +338,24 @@ bitmap_ip_timeout_head(struct ip_set *set, struct sk_buff *skb)
        NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP_TO, htonl(map->last_ip));
        if (map->netmask != 32)
                NLA_PUT_U8(skb, IPSET_ATTR_NETMASK, map->netmask);
-       NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT, htonl(map->timeout));
        NLA_PUT_NET32(skb, IPSET_ATTR_REFERENCES,
                      htonl(atomic_read(&set->ref) - 1));
        NLA_PUT_NET32(skb, IPSET_ATTR_MEMSIZE,
                      htonl(sizeof(*map) + map->memsize));
+       if (with_timeout(map->timeout))
+               NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT, htonl(map->timeout));
        ipset_nest_end(skb, nested);
 
        return 0;
 nla_put_failure:
-       return -EFAULT;
-}
-
-static int
-bitmap_ip_timeout_list(const struct ip_set *set,
-                      struct sk_buff *skb, struct netlink_callback *cb)
-{
-       const struct bitmap_ip_timeout *map = set->data;
-       struct nlattr *adt, *nested;
-       u32 id, first = cb->args[2];
-       const unsigned long *table = map->members;
-
-       adt = ipset_nest_start(skb, IPSET_ATTR_ADT);
-       if (!adt)
-               return -EFAULT;
-       for (; cb->args[2] < map->elements; cb->args[2]++) {
-               id = cb->args[2];
-               if (!bitmap_ip_timeout_test(map, id))
-                       continue;
-               nested = ipset_nest_start(skb, IPSET_ATTR_DATA);
-               if (!nested) {
-                       if (id == first) {
-                               nla_nest_cancel(skb, adt);
-                               return -EFAULT;
-                       } else
-                               goto nla_put_failure;
-               }
-               NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP,
-                               htonl(map->first_ip + id * map->hosts));
-               NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT,
-                             htonl(ip_set_timeout_get(table[id])));
-               ipset_nest_end(skb, nested);
-       }
-       ipset_nest_end(skb, adt);
-
-       /* Set listing finished */
-       cb->args[2] = 0;
-
-       return 0;
-
-nla_put_failure:
-       nla_nest_cancel(skb, nested);
-       ipset_nest_end(skb, adt);
-       return 0;
+       return -EMSGSIZE;
 }
 
 static bool
-bitmap_ip_timeout_same_set(const struct ip_set *a, const struct ip_set *b)
+bitmap_ip_same_set(const struct ip_set *a, const struct ip_set *b)
 {
-       const struct bitmap_ip_timeout *x = a->data;
-       const struct bitmap_ip_timeout *y = b->data;
+       const struct bitmap_ip *x = a->data;
+       const struct bitmap_ip *y = b->data;
 
        return x->first_ip == y->first_ip &&
               x->last_ip == y->last_ip &&
@@ -519,21 +363,41 @@ bitmap_ip_timeout_same_set(const struct ip_set *a, const struct ip_set *b)
               x->timeout == y->timeout;
 }
 
-static const struct ip_set_type_variant bitmap_ip_timeout = {
-       .kadt   = bitmap_ip_timeout_kadt,
-       .uadt   = bitmap_ip_timeout_uadt,
-       .destroy = bitmap_ip_timeout_destroy,
-       .flush  = bitmap_ip_timeout_flush,
-       .head   = bitmap_ip_timeout_head,
-       .list   = bitmap_ip_timeout_list,
-       .same_set = bitmap_ip_timeout_same_set,
+static const struct ip_set_type_variant bitmap_ip = {
+       .kadt   = bitmap_ip_kadt,
+       .uadt   = bitmap_ip_uadt,
+       .adt    = {
+               [IPSET_ADD] = bitmap_ip_add,
+               [IPSET_DEL] = bitmap_ip_del,
+               [IPSET_TEST] = bitmap_ip_test,
+       },
+       .destroy = bitmap_ip_destroy,
+       .flush  = bitmap_ip_flush,
+       .head   = bitmap_ip_head,
+       .list   = bitmap_ip_list,
+       .same_set = bitmap_ip_same_set,
+};
+
+static const struct ip_set_type_variant bitmap_tip = {
+       .kadt   = bitmap_ip_kadt,
+       .uadt   = bitmap_ip_uadt,
+       .adt    = {
+               [IPSET_ADD] = bitmap_ip_tadd,
+               [IPSET_DEL] = bitmap_ip_tdel,
+               [IPSET_TEST] = bitmap_ip_ttest,
+       },
+       .destroy = bitmap_ip_destroy,
+       .flush  = bitmap_ip_flush,
+       .head   = bitmap_ip_head,
+       .list   = bitmap_ip_tlist,
+       .same_set = bitmap_ip_same_set,
 };
 
 static void
 bitmap_ip_gc(unsigned long ul_set)
 {
        struct ip_set *set = (struct ip_set *) ul_set;
-       struct bitmap_ip_timeout *map = set->data;
+       struct bitmap_ip *map = set->data;
        unsigned long *table = map->members;
        u32 id;
 
@@ -552,7 +416,7 @@ bitmap_ip_gc(unsigned long ul_set)
 static void
 bitmap_ip_gc_init(struct ip_set *set)
 {
-       struct bitmap_ip_timeout *map = set->data;
+       struct bitmap_ip *map = set->data;
 
        init_timer(&map->gc);
        map->gc.data = (unsigned long) set;
@@ -563,21 +427,12 @@ bitmap_ip_gc_init(struct ip_set *set)
 
 /* Create bitmap:ip type of sets */
 
-static const struct nla_policy
-bitmap_ip_create_policy[IPSET_ATTR_CREATE_MAX+1] = {
-       [IPSET_ATTR_IP]         = { .type = NLA_NESTED },
-       [IPSET_ATTR_IP_TO]      = { .type = NLA_NESTED },
-       [IPSET_ATTR_CIDR]       = { .type = NLA_U8 },
-       [IPSET_ATTR_NETMASK]    = { .type = NLA_U8  },
-       [IPSET_ATTR_TIMEOUT]    = { .type = NLA_U32 },
-};
-
 static bool
 init_map_ip(struct ip_set *set, struct bitmap_ip *map,
            u32 first_ip, u32 last_ip,
            u32 elements, u32 hosts, u8 netmask)
 {
-       map->members = ip_set_alloc(map->memsize, GFP_KERNEL);
+       map->members = ip_set_alloc(map->memsize);
        if (!map->members)
                return false;
        map->first_ip = first_ip;
@@ -585,6 +440,7 @@ init_map_ip(struct ip_set *set, struct bitmap_ip *map,
        map->elements = elements;
        map->hosts = hosts;
        map->netmask = netmask;
+       map->timeout = IPSET_NO_TIMEOUT;
 
        set->data = map;
        set->family = AF_INET;
@@ -593,18 +449,13 @@ init_map_ip(struct ip_set *set, struct bitmap_ip *map,
 }
 
 static int
-bitmap_ip_create(struct ip_set *set, struct nlattr *head, int len,
-                u32 flags)
+bitmap_ip_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
 {
-       struct nlattr *tb[IPSET_ATTR_CREATE_MAX+1];
+       struct bitmap_ip *map;
        u32 first_ip, last_ip, hosts, elements;
        u8 netmask = 32;
        int ret;
 
-       if (nla_parse(tb, IPSET_ATTR_CREATE_MAX, head, len,
-                     bitmap_ip_create_policy))
-               return -IPSET_ERR_PROTOCOL;
-
        if (unlikely(!tb[IPSET_ATTR_IP] ||
                     !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
                return -IPSET_ERR_PROTOCOL;
@@ -664,37 +515,27 @@ bitmap_ip_create(struct ip_set *set, struct nlattr *head, int len,
 
        pr_debug("hosts %u, elements %u\n", hosts, elements);
 
-       if (tb[IPSET_ATTR_TIMEOUT]) {
-               struct bitmap_ip_timeout *map;
-
-               map = kzalloc(sizeof(*map), GFP_KERNEL);
-               if (!map)
-                       return -ENOMEM;
+       map = kzalloc(sizeof(*map), GFP_KERNEL);
+       if (!map)
+               return -ENOMEM;
 
+       if (tb[IPSET_ATTR_TIMEOUT]) {
                map->memsize = elements * sizeof(unsigned long);
 
-               if (!init_map_ip(set, (struct bitmap_ip *)map,
-                                first_ip, last_ip,
+               if (!init_map_ip(set, map, first_ip, last_ip,
                                 elements, hosts, netmask)) {
                        kfree(map);
                        return -ENOMEM;
                }
 
                map->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
-               set->variant = &bitmap_ip_timeout;
+               set->variant = &bitmap_tip;
 
                bitmap_ip_gc_init(set);
        } else {
-               struct bitmap_ip *map;
-
-               map = kzalloc(sizeof(*map), GFP_KERNEL);
-               if (!map)
-                       return -ENOMEM;
-
                map->memsize = bitmap_bytes(0, elements - 1);
 
-               if (!init_map_ip(set, map,
-                                first_ip, last_ip,
+               if (!init_map_ip(set, map, first_ip, last_ip,
                                 elements, hosts, netmask)) {
                        kfree(map);
                        return -ENOMEM;
@@ -713,6 +554,20 @@ static struct ip_set_type bitmap_ip_type __read_mostly = {
        .family         = AF_INET,
        .revision       = 0,
        .create         = bitmap_ip_create,
+       .create_policy  = {
+               [IPSET_ATTR_IP]         = { .type = NLA_NESTED },
+               [IPSET_ATTR_IP_TO]      = { .type = NLA_NESTED },
+               [IPSET_ATTR_CIDR]       = { .type = NLA_U8 },
+               [IPSET_ATTR_NETMASK]    = { .type = NLA_U8  },
+               [IPSET_ATTR_TIMEOUT]    = { .type = NLA_U32 },
+       },
+       .adt_policy     = {
+               [IPSET_ATTR_IP]         = { .type = NLA_NESTED },
+               [IPSET_ATTR_IP_TO]      = { .type = NLA_NESTED },
+               [IPSET_ATTR_CIDR]       = { .type = NLA_U8 },
+               [IPSET_ATTR_TIMEOUT]    = { .type = NLA_U32 },
+               [IPSET_ATTR_LINENO]     = { .type = NLA_U32 },
+       },
        .me             = THIS_MODULE,
 };
 
index 736352794985153818d65e467bad4db14a1125f5..50fcb3f98324dd7137187b623e1952f2f7de131e 100644 (file)
@@ -15,9 +15,6 @@
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
 #include <linux/errno.h>
-#include <linux/uaccess.h>
-#include <linux/bitops.h>
-#include <linux/spinlock.h>
 #include <linux/if_ether.h>
 #include <linux/netlink.h>
 #include <linux/jiffies.h>
@@ -175,7 +172,7 @@ bitmap_ipmac_list(const struct ip_set *set,
 
        atd = ipset_nest_start(skb, IPSET_ATTR_ADT);
        if (!atd)
-               return -EFAULT;
+               return -EMSGSIZE;
        for (; cb->args[2] <= last; cb->args[2]++) {
                id = cb->args[2];
                elem = bitmap_ipmac_elem(map, id);
@@ -185,7 +182,7 @@ bitmap_ipmac_list(const struct ip_set *set,
                if (!nested) {
                        if (id == first) {
                                nla_nest_cancel(skb, atd);
-                               return -EFAULT;
+                               return -EMSGSIZE;
                        } else
                                goto nla_put_failure;
                }
@@ -205,6 +202,10 @@ bitmap_ipmac_list(const struct ip_set *set,
 nla_put_failure:
        nla_nest_cancel(skb, nested);
        ipset_nest_end(skb, atd);
+       if (unlikely(id == first)) {
+               cb->args[2] = 0;
+               return -EMSGSIZE;
+       }
        return 0;
 }
 
@@ -298,7 +299,7 @@ bitmap_ipmac_tlist(const struct ip_set *set,
 
        atd = ipset_nest_start(skb, IPSET_ATTR_ADT);
        if (!atd)
-               return -EFAULT;
+               return -EMSGSIZE;
        for (; cb->args[2] <= last; cb->args[2]++) {
                id = cb->args[2];
                elem = bitmap_ipmac_elem(map, id);
@@ -308,7 +309,7 @@ bitmap_ipmac_tlist(const struct ip_set *set,
                if (!nested) {
                        if (id == first) {
                                nla_nest_cancel(skb, atd);
-                               return -EFAULT;
+                               return -EMSGSIZE;
                        } else
                                goto nla_put_failure;
                }
@@ -331,7 +332,7 @@ bitmap_ipmac_tlist(const struct ip_set *set,
 nla_put_failure:
        nla_nest_cancel(skb, nested);
        ipset_nest_end(skb, atd);
-       return 0;
+       return -EMSGSIZE;
 }
 
 static int
@@ -357,29 +358,16 @@ bitmap_ipmac_kadt(struct ip_set *set, const struct sk_buff *skb,
        return adtfn(set, &data, map->timeout);
 }
 
-static const struct nla_policy
-bitmap_ipmac_adt_policy[IPSET_ATTR_ADT_MAX + 1] = {
-       [IPSET_ATTR_IP]         = { .type = NLA_NESTED },
-       [IPSET_ATTR_ETHER]      = { .type = NLA_BINARY, .len  = ETH_ALEN },
-       [IPSET_ATTR_TIMEOUT]    = { .type = NLA_U32 },
-       [IPSET_ATTR_LINENO]     = { .type = NLA_U32 },
-};
-
 static int
-bitmap_ipmac_uadt(struct ip_set *set, struct nlattr *head, int len,
+bitmap_ipmac_uadt(struct ip_set *set, struct nlattr *tb[],
                  enum ipset_adt adt, u32 *lineno, u32 flags)
 {
        const struct bitmap_ipmac *map = set->data;
-       struct nlattr *tb[IPSET_ATTR_ADT_MAX+1];
        ipset_adtfn adtfn = set->variant->adt[adt];
        struct ipmac data;
        u32 timeout = map->timeout;
        int ret = 0;
 
-       if (nla_parse(tb, IPSET_ATTR_ADT_MAX, head, len,
-                     bitmap_ipmac_adt_policy))
-               return -IPSET_ERR_PROTOCOL;
-
        if (unlikely(!tb[IPSET_ATTR_IP] ||
                     !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
                return -IPSET_ERR_PROTOCOL;
@@ -457,7 +445,7 @@ bitmap_ipmac_head(struct ip_set *set, struct sk_buff *skb)
 
        return 0;
 nla_put_failure:
-       return -EFAULT;
+       return -EMSGSIZE;
 }
 
 static bool
@@ -538,20 +526,11 @@ bitmap_ipmac_gc_init(struct ip_set *set)
 
 /* Create bitmap:ip,mac type of sets */
 
-static const struct nla_policy
-bitmap_ipmac_create_policy[IPSET_ATTR_CREATE_MAX+1] = {
-       [IPSET_ATTR_IP]         = { .type = NLA_NESTED },
-       [IPSET_ATTR_IP_TO]      = { .type = NLA_NESTED },
-       [IPSET_ATTR_CIDR]       = { .type = NLA_U8 },
-       [IPSET_ATTR_TIMEOUT]    = { .type = NLA_U32 },
-};
-
 static bool
 init_map_ipmac(struct ip_set *set, struct bitmap_ipmac *map,
               u32 first_ip, u32 last_ip)
 {
-       map->members = ip_set_alloc((last_ip - first_ip + 1) * map->dsize,
-                                   GFP_KERNEL);
+       map->members = ip_set_alloc((last_ip - first_ip + 1) * map->dsize);
        if (!map->members)
                return false;
        map->first_ip = first_ip;
@@ -565,18 +544,13 @@ init_map_ipmac(struct ip_set *set, struct bitmap_ipmac *map,
 }
 
 static int
-bitmap_ipmac_create(struct ip_set *set, struct nlattr *head, int len,
+bitmap_ipmac_create(struct ip_set *set, struct nlattr *tb[],
                    u32 flags)
 {
-       struct nlattr *tb[IPSET_ATTR_CREATE_MAX+1];
        u32 first_ip, last_ip, elements;
        struct bitmap_ipmac *map;
        int ret;
 
-       if (nla_parse(tb, IPSET_ATTR_CREATE_MAX, head, len,
-                     bitmap_ipmac_create_policy))
-               return -IPSET_ERR_PROTOCOL;
-
        if (unlikely(!tb[IPSET_ATTR_IP] ||
                     !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
                return -IPSET_ERR_PROTOCOL;
@@ -647,6 +621,18 @@ static struct ip_set_type bitmap_ipmac_type = {
        .family         = AF_INET,
        .revision       = 0,
        .create         = bitmap_ipmac_create,
+       .create_policy  = {
+               [IPSET_ATTR_IP]         = { .type = NLA_NESTED },
+               [IPSET_ATTR_IP_TO]      = { .type = NLA_NESTED },
+               [IPSET_ATTR_CIDR]       = { .type = NLA_U8 },
+               [IPSET_ATTR_TIMEOUT]    = { .type = NLA_U32 },
+       },
+       .adt_policy     = {
+               [IPSET_ATTR_IP]         = { .type = NLA_NESTED },
+               [IPSET_ATTR_ETHER]      = { .type = NLA_BINARY, .len  = ETH_ALEN },
+               [IPSET_ATTR_TIMEOUT]    = { .type = NLA_U32 },
+               [IPSET_ATTR_LINENO]     = { .type = NLA_U32 },
+       },
        .me             = THIS_MODULE,
 };
 
index 5c5c6f393ce91058f864bb87e931b71548275a8b..01dc2ff52c8c606e490f5b3b835bc1af1112eaf8 100644 (file)
@@ -9,13 +9,8 @@
 
 #include <linux/module.h>
 #include <linux/ip.h>
-#include <linux/tcp.h>
-#include <linux/udp.h>
 #include <linux/skbuff.h>
 #include <linux/errno.h>
-#include <linux/uaccess.h>
-#include <linux/bitops.h>
-#include <linux/spinlock.h>
 #include <linux/netlink.h>
 #include <linux/jiffies.h>
 #include <linux/timer.h>
@@ -32,172 +27,49 @@ MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
 MODULE_DESCRIPTION("bitmap:port type of IP sets");
 MODULE_ALIAS("ip_set_bitmap:port");
 
-/* Base variant */
-
+/* Type structure */
 struct bitmap_port {
        void *members;          /* the set members */
        u16 first_port;         /* host byte order, included in range */
        u16 last_port;          /* host byte order, included in range */
        size_t memsize;         /* members size */
+       u32 timeout;            /* timeout parameter */
+       struct timer_list gc;   /* garbage collection */
 };
 
-static inline int
-bitmap_port_test(const struct bitmap_port *map, u16 id)
-{
-       return !!test_bit(id, map->members);
-}
-
-static inline int
-bitmap_port_add(struct bitmap_port *map, u16 id)
-{
-       if (test_and_set_bit(id, map->members))
-               return -IPSET_ERR_EXIST;
-
-       return 0;
-}
+/* Base variant */
 
 static int
-bitmap_port_del(struct bitmap_port *map, u16 id)
+bitmap_port_test(struct ip_set *set, void *value, u32 timeout)
 {
-       if (!test_and_clear_bit(id, map->members))
-               return -IPSET_ERR_EXIST;
+       const struct bitmap_port *map = set->data;
+       u16 id = *(u16 *)value;
 
-       return 0;
+       return !!test_bit(id, map->members);
 }
 
 static int
-bitmap_port_kadt(struct ip_set *set, const struct sk_buff *skb,
-                enum ipset_adt adt, u8 pf, u8 dim, u8 flags)
+bitmap_port_add(struct ip_set *set, void *value, u32 timeout)
 {
        struct bitmap_port *map = set->data;
-       __be16 __port;
-       u16 port = 0;
-
-       if (!ip_set_get_ip_port(skb, pf, flags & IPSET_DIM_ONE_SRC, &__port))
-               return -EINVAL;
+       u16 id = *(u16 *)value;
 
-       port = ntohs(__port);
-
-       if (port < map->first_port || port > map->last_port)
-               return -IPSET_ERR_BITMAP_RANGE;
-
-       port -= map->first_port;
+       if (test_and_set_bit(id, map->members))
+               return -IPSET_ERR_EXIST;
 
-       switch (adt) {
-       case IPSET_TEST:
-               return bitmap_port_test(map, port);
-       case IPSET_ADD:
-               return bitmap_port_add(map, port);
-       case IPSET_DEL:
-               return bitmap_port_del(map, port);
-       default:
-               return -EINVAL;
-       }
+       return 0;
 }
 
-static const struct nla_policy bitmap_port_adt_policy[IPSET_ATTR_ADT_MAX+1] = {
-       [IPSET_ATTR_PORT]       = { .type = NLA_U16 },
-       [IPSET_ATTR_PORT_TO]    = { .type = NLA_U16 },
-       [IPSET_ATTR_TIMEOUT]    = { .type = NLA_U32 },
-       [IPSET_ATTR_LINENO]     = { .type = NLA_U32 },
-};
-
 static int
-bitmap_port_uadt(struct ip_set *set, struct nlattr *head, int len,
-                enum ipset_adt adt, u32 *lineno, u32 flags)
+bitmap_port_del(struct ip_set *set, void *value, u32 timeout)
 {
        struct bitmap_port *map = set->data;
-       struct nlattr *tb[IPSET_ATTR_ADT_MAX+1];
-       u32 port;       /* wraparound */
-       u16 id, port_to;
-       int ret = 0;
-
-       if (nla_parse(tb, IPSET_ATTR_ADT_MAX, head, len,
-                     bitmap_port_adt_policy))
-               return -IPSET_ERR_PROTOCOL;
-
-       if (unlikely(!ip_set_attr_netorder(tb, IPSET_ATTR_PORT) ||
-                    !ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO)))
-               return -IPSET_ERR_PROTOCOL;
-
-       if (tb[IPSET_ATTR_LINENO])
-               *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
-
-       port = ip_set_get_h16(tb[IPSET_ATTR_PORT]);
-       if (port < map->first_port || port > map->last_port)
-               return -IPSET_ERR_BITMAP_RANGE;
-
-       if (tb[IPSET_ATTR_TIMEOUT])
-               return -IPSET_ERR_TIMEOUT;
-
-       if (adt == IPSET_TEST)
-               return bitmap_port_test(map, port - map->first_port);
-
-       if (tb[IPSET_ATTR_PORT_TO]) {
-               port_to = ip_set_get_h16(tb[IPSET_ATTR_PORT_TO]);
-               if (port > port_to) {
-                       swap(port, port_to);
-                       if (port < map->first_port)
-                               return -IPSET_ERR_BITMAP_RANGE;
-               }
-       } else
-               port_to = port;
+       u16 id = *(u16 *)value;
 
-       if (port_to > map->last_port)
-               return -IPSET_ERR_BITMAP_RANGE;
-
-       for (; port <= port_to; port++) {
-               id = port - map->first_port;
-               ret = adt == IPSET_ADD ? bitmap_port_add(map, id)
-                                      : bitmap_port_del(map, id);
-
-               if (ret && !ip_set_eexist(ret, flags))
-                       return ret;
-               else
-                       ret = 0;
-       }
-       return ret;
-}
-
-static void
-bitmap_port_destroy(struct ip_set *set)
-{
-       struct bitmap_port *map = set->data;
-
-       ip_set_free(map->members);
-       kfree(map);
-
-       set->data = NULL;
-}
-
-static void
-bitmap_port_flush(struct ip_set *set)
-{
-       struct bitmap_port *map = set->data;
-
-       memset(map->members, 0, map->memsize);
-}
-
-static int
-bitmap_port_head(struct ip_set *set, struct sk_buff *skb)
-{
-       const struct bitmap_port *map = set->data;
-       struct nlattr *nested;
-
-       nested = ipset_nest_start(skb, IPSET_ATTR_DATA);
-       if (!nested)
-               goto nla_put_failure;
-       NLA_PUT_NET16(skb, IPSET_ATTR_PORT, htons(map->first_port));
-       NLA_PUT_NET16(skb, IPSET_ATTR_PORT_TO, htons(map->last_port));
-       NLA_PUT_NET32(skb, IPSET_ATTR_REFERENCES,
-                     htonl(atomic_read(&set->ref) - 1));
-       NLA_PUT_NET32(skb, IPSET_ATTR_MEMSIZE,
-                     htonl(sizeof(*map) + map->memsize));
-       ipset_nest_end(skb, nested);
+       if (!test_and_clear_bit(id, map->members))
+               return -IPSET_ERR_EXIST;
 
        return 0;
-nla_put_failure:
-       return -EFAULT;
 }
 
 static int
@@ -211,7 +83,7 @@ bitmap_port_list(const struct ip_set *set,
 
        atd = ipset_nest_start(skb, IPSET_ATTR_ADT);
        if (!atd)
-               return -EFAULT;
+               return -EMSGSIZE;
        for (; cb->args[2] <= last; cb->args[2]++) {
                id = cb->args[2];
                if (!test_bit(id, map->members))
@@ -220,7 +92,7 @@ bitmap_port_list(const struct ip_set *set,
                if (!nested) {
                        if (id == first) {
                                nla_nest_cancel(skb, atd);
-                               return -EFAULT;
+                               return -EMSGSIZE;
                        } else
                                goto nla_put_failure;
                }
@@ -237,77 +109,109 @@ bitmap_port_list(const struct ip_set *set,
 nla_put_failure:
        nla_nest_cancel(skb, nested);
        ipset_nest_end(skb, atd);
+       if (unlikely(id == first)) {
+               cb->args[2] = 0;
+               return -EMSGSIZE;
+       }
        return 0;
 }
 
-static bool
-bitmap_port_same_set(const struct ip_set *a, const struct ip_set *b)
-{
-       const struct bitmap_port *x = a->data;
-       const struct bitmap_port *y = b->data;
-
-       return x->first_port == y->first_port &&
-              x->last_port == y->last_port;
-}
-
-static const struct ip_set_type_variant bitmap_port = {
-       .kadt   = bitmap_port_kadt,
-       .uadt   = bitmap_port_uadt,
-       .destroy = bitmap_port_destroy,
-       .flush  = bitmap_port_flush,
-       .head   = bitmap_port_head,
-       .list   = bitmap_port_list,
-       .same_set = bitmap_port_same_set,
-};
-
 /* Timeout variant */
 
-struct bitmap_port_timeout {
-       unsigned long *members; /* the set members */
-       u16 first_port;         /* host byte order, included in range */
-       u16 last_port;          /* host byte order, included in range */
-       size_t memsize;         /* members size */
-
-       u32 timeout;            /* timeout parameter */
-       struct timer_list gc;   /* garbage collection */
-};
-
-static inline bool
-bitmap_port_timeout_test(const struct bitmap_port_timeout *map, u16 id)
+static int
+bitmap_port_ttest(struct ip_set *set, void *value, u32 timeout)
 {
-       return ip_set_timeout_test(map->members[id]);
+       const struct bitmap_port *map = set->data;
+       const unsigned long *members = map->members;
+       u16 id = *(u16 *)value;
+
+       return ip_set_timeout_test(members[id]);
 }
 
 static int
-bitmap_port_timeout_add(const struct bitmap_port_timeout *map,
-                       u16 id, u32 timeout)
+bitmap_port_tadd(struct ip_set *set, void *value, u32 timeout)
 {
-       if (bitmap_port_timeout_test(map, id))
+       struct bitmap_port *map = set->data;
+       unsigned long *members = map->members;
+       u16 id = *(u16 *)value;
+
+       if (ip_set_timeout_test(members[id]))
                return -IPSET_ERR_EXIST;
 
-       map->members[id] = ip_set_timeout_set(timeout);
+       members[id] = ip_set_timeout_set(timeout);
 
        return 0;
 }
 
 static int
-bitmap_port_timeout_del(const struct bitmap_port_timeout *map,
-                       u16 id)
+bitmap_port_tdel(struct ip_set *set, void *value, u32 timeout)
 {
+       struct bitmap_port *map = set->data;
+       unsigned long *members = map->members;
+       u16 id = *(u16 *)value;
        int ret = -IPSET_ERR_EXIST;
 
-       if (bitmap_port_timeout_test(map, id))
+       if (ip_set_timeout_test(members[id]))
                ret = 0;
 
-       map->members[id] = IPSET_ELEM_UNSET;
+       members[id] = IPSET_ELEM_UNSET;
        return ret;
 }
 
 static int
-bitmap_port_timeout_kadt(struct ip_set *set, const struct sk_buff *skb,
-                        enum ipset_adt adt, u8 pf, u8 dim, u8 flags)
+bitmap_port_tlist(const struct ip_set *set,
+                 struct sk_buff *skb, struct netlink_callback *cb)
+{
+       const struct bitmap_port *map = set->data;
+       struct nlattr *adt, *nested;
+       u16 id, first = cb->args[2];
+       u16 last = map->last_port - map->first_port;
+       const unsigned long *members = map->members;
+
+       adt = ipset_nest_start(skb, IPSET_ATTR_ADT);
+       if (!adt)
+               return -EMSGSIZE;
+       for (; cb->args[2] <= last; cb->args[2]++) {
+               id = cb->args[2];
+               if (!ip_set_timeout_test(members[id]))
+                       continue;
+               nested = ipset_nest_start(skb, IPSET_ATTR_DATA);
+               if (!nested) {
+                       if (id == first) {
+                               nla_nest_cancel(skb, adt);
+                               return -EMSGSIZE;
+                       } else
+                               goto nla_put_failure;
+               }
+               NLA_PUT_NET16(skb, IPSET_ATTR_PORT,
+                             htons(map->first_port + id));
+               NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT,
+                             htonl(ip_set_timeout_get(members[id])));
+               ipset_nest_end(skb, nested);
+       }
+       ipset_nest_end(skb, adt);
+
+       /* Set listing finished */
+       cb->args[2] = 0;
+
+       return 0;
+
+nla_put_failure:
+       nla_nest_cancel(skb, nested);
+       ipset_nest_end(skb, adt);
+       if (unlikely(id == first)) {
+               cb->args[2] = 0;
+               return -EMSGSIZE;
+       }
+       return 0;
+}
+
+static int
+bitmap_port_kadt(struct ip_set *set, const struct sk_buff *skb,
+                enum ipset_adt adt, u8 pf, u8 dim, u8 flags)
 {
-       struct bitmap_port_timeout *map = set->data;
+       struct bitmap_port *map = set->data;
+       ipset_adtfn adtfn = set->variant->adt[adt];
        __be16 __port;
        u16 port = 0;
 
@@ -321,32 +225,20 @@ bitmap_port_timeout_kadt(struct ip_set *set, const struct sk_buff *skb,
 
        port -= map->first_port;
 
-       switch (adt) {
-       case IPSET_TEST:
-               return bitmap_port_timeout_test(map, port);
-       case IPSET_ADD:
-               return bitmap_port_timeout_add(map, port, map->timeout);
-       case IPSET_DEL:
-               return bitmap_port_timeout_del(map, port);
-       default:
-               return -EINVAL;
-       }
+       return adtfn(set, &port, map->timeout);
 }
 
 static int
-bitmap_port_timeout_uadt(struct ip_set *set, struct nlattr *head, int len,
-                        enum ipset_adt adt, u32 *lineno, u32 flags)
+bitmap_port_uadt(struct ip_set *set, struct nlattr *tb[],
+                enum ipset_adt adt, u32 *lineno, u32 flags)
 {
-       const struct bitmap_port_timeout *map = set->data;
-       struct nlattr *tb[IPSET_ATTR_ADT_MAX+1];
+       struct bitmap_port *map = set->data;
+       ipset_adtfn adtfn = set->variant->adt[adt];
+       u32 timeout = map->timeout;
+       u32 port;       /* wraparound */
        u16 id, port_to;
-       u32 port, timeout = map->timeout;       /* wraparound */
        int ret = 0;
 
-       if (nla_parse(tb, IPSET_ATTR_ADT_MAX, head, len,
-                     bitmap_port_adt_policy))
-               return -IPSET_ERR_PROTOCOL;
-
        if (unlikely(!ip_set_attr_netorder(tb, IPSET_ATTR_PORT) ||
                     !ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO) ||
                     !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
@@ -359,8 +251,16 @@ bitmap_port_timeout_uadt(struct ip_set *set, struct nlattr *head, int len,
        if (port < map->first_port || port > map->last_port)
                return -IPSET_ERR_BITMAP_RANGE;
 
-       if (adt == IPSET_TEST)
-               return bitmap_port_timeout_test(map, port - map->first_port);
+       if (tb[IPSET_ATTR_TIMEOUT]) {
+               if (!with_timeout(map->timeout))
+                       return -IPSET_ERR_TIMEOUT;
+               timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
+       }
+
+       if (adt == IPSET_TEST) {
+               id = port - map->first_port;
+               return adtfn(set, &id, timeout);
+       }
 
        if (tb[IPSET_ATTR_PORT_TO]) {
                port_to = ip_set_get_h16(tb[IPSET_ATTR_PORT_TO]);
@@ -375,14 +275,9 @@ bitmap_port_timeout_uadt(struct ip_set *set, struct nlattr *head, int len,
        if (port_to > map->last_port)
                return -IPSET_ERR_BITMAP_RANGE;
 
-       if (tb[IPSET_ATTR_TIMEOUT])
-               timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
-
        for (; port <= port_to; port++) {
                id = port - map->first_port;
-               ret = adt == IPSET_ADD
-                       ? bitmap_port_timeout_add(map, id, timeout)
-                       : bitmap_port_timeout_del(map, id);
+               ret = adtfn(set, &id, timeout);
 
                if (ret && !ip_set_eexist(ret, flags))
                        return ret;
@@ -393,11 +288,13 @@ bitmap_port_timeout_uadt(struct ip_set *set, struct nlattr *head, int len,
 }
 
 static void
-bitmap_port_timeout_destroy(struct ip_set *set)
+bitmap_port_destroy(struct ip_set *set)
 {
-       struct bitmap_port_timeout *map = set->data;
+       struct bitmap_port *map = set->data;
+
+       if (with_timeout(map->timeout))
+               del_timer_sync(&map->gc);
 
-       del_timer_sync(&map->gc);
        ip_set_free(map->members);
        kfree(map);
 
@@ -405,17 +302,17 @@ bitmap_port_timeout_destroy(struct ip_set *set)
 }
 
 static void
-bitmap_port_timeout_flush(struct ip_set *set)
+bitmap_port_flush(struct ip_set *set)
 {
-       struct bitmap_port_timeout *map = set->data;
+       struct bitmap_port *map = set->data;
 
        memset(map->members, 0, map->memsize);
 }
 
 static int
-bitmap_port_timeout_head(struct ip_set *set, struct sk_buff *skb)
+bitmap_port_head(struct ip_set *set, struct sk_buff *skb)
 {
-       const struct bitmap_port_timeout *map = set->data;
+       const struct bitmap_port *map = set->data;
        struct nlattr *nested;
 
        nested = ipset_nest_start(skb, IPSET_ATTR_DATA);
@@ -423,88 +320,65 @@ bitmap_port_timeout_head(struct ip_set *set, struct sk_buff *skb)
                goto nla_put_failure;
        NLA_PUT_NET16(skb, IPSET_ATTR_PORT, htons(map->first_port));
        NLA_PUT_NET16(skb, IPSET_ATTR_PORT_TO, htons(map->last_port));
-       NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT , htonl(map->timeout));
        NLA_PUT_NET32(skb, IPSET_ATTR_REFERENCES,
                      htonl(atomic_read(&set->ref) - 1));
        NLA_PUT_NET32(skb, IPSET_ATTR_MEMSIZE,
                      htonl(sizeof(*map) + map->memsize));
+       if (with_timeout(map->timeout))
+               NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT, htonl(map->timeout));
        ipset_nest_end(skb, nested);
 
        return 0;
 nla_put_failure:
-       return -EFAULT;
-}
-
-static int
-bitmap_port_timeout_list(const struct ip_set *set,
-                        struct sk_buff *skb, struct netlink_callback *cb)
-{
-       const struct bitmap_port_timeout *map = set->data;
-       struct nlattr *adt, *nested;
-       u16 id, first = cb->args[2];
-       u16 last = map->last_port - map->first_port;
-       const unsigned long *table = map->members;
-
-       adt = ipset_nest_start(skb, IPSET_ATTR_ADT);
-       if (!adt)
-               return -EFAULT;
-       for (; cb->args[2] <= last; cb->args[2]++) {
-               id = cb->args[2];
-               if (!bitmap_port_timeout_test(map, id))
-                       continue;
-               nested = ipset_nest_start(skb, IPSET_ATTR_DATA);
-               if (!nested) {
-                       if (id == first) {
-                               nla_nest_cancel(skb, adt);
-                               return -EFAULT;
-                       } else
-                               goto nla_put_failure;
-               }
-               NLA_PUT_NET16(skb, IPSET_ATTR_PORT,
-                             htons(map->first_port + id));
-               NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT,
-                             htonl(ip_set_timeout_get(table[id])));
-               ipset_nest_end(skb, nested);
-       }
-       ipset_nest_end(skb, adt);
-
-       /* Set listing finished */
-       cb->args[2] = 0;
-
-       return 0;
-
-nla_put_failure:
-       nla_nest_cancel(skb, nested);
-       ipset_nest_end(skb, adt);
-       return 0;
+       return -EMSGSIZE;
 }
 
 static bool
-bitmap_port_timeout_same_set(const struct ip_set *a, const struct ip_set *b)
+bitmap_port_same_set(const struct ip_set *a, const struct ip_set *b)
 {
-       const struct bitmap_port_timeout *x = a->data;
-       const struct bitmap_port_timeout *y = b->data;
+       const struct bitmap_port *x = a->data;
+       const struct bitmap_port *y = b->data;
 
        return x->first_port == y->first_port &&
               x->last_port == y->last_port &&
               x->timeout == y->timeout;
 }
 
-static const struct ip_set_type_variant bitmap_port_timeout = {
-       .kadt   = bitmap_port_timeout_kadt,
-       .uadt   = bitmap_port_timeout_uadt,
-       .destroy = bitmap_port_timeout_destroy,
-       .flush  = bitmap_port_timeout_flush,
-       .head   = bitmap_port_timeout_head,
-       .list   = bitmap_port_timeout_list,
-       .same_set = bitmap_port_timeout_same_set,
+static const struct ip_set_type_variant bitmap_port = {
+       .kadt   = bitmap_port_kadt,
+       .uadt   = bitmap_port_uadt,
+       .adt    = {
+               [IPSET_ADD] = bitmap_port_add,
+               [IPSET_DEL] = bitmap_port_del,
+               [IPSET_TEST] = bitmap_port_test,
+       },
+       .destroy = bitmap_port_destroy,
+       .flush  = bitmap_port_flush,
+       .head   = bitmap_port_head,
+       .list   = bitmap_port_list,
+       .same_set = bitmap_port_same_set,
+};
+
+static const struct ip_set_type_variant bitmap_tport = {
+       .kadt   = bitmap_port_kadt,
+       .uadt   = bitmap_port_uadt,
+       .adt    = {
+               [IPSET_ADD] = bitmap_port_tadd,
+               [IPSET_DEL] = bitmap_port_tdel,
+               [IPSET_TEST] = bitmap_port_ttest,
+       },
+       .destroy = bitmap_port_destroy,
+       .flush  = bitmap_port_flush,
+       .head   = bitmap_port_head,
+       .list   = bitmap_port_tlist,
+       .same_set = bitmap_port_same_set,
 };
 
 static void
 bitmap_port_gc(unsigned long ul_set)
 {
        struct ip_set *set = (struct ip_set *) ul_set;
-       struct bitmap_port_timeout *map = set->data;
+       struct bitmap_port *map = set->data;
        unsigned long *table = map->members;
        u32 id; /* wraparound */
        u16 last = map->last_port - map->first_port;
@@ -524,7 +398,7 @@ bitmap_port_gc(unsigned long ul_set)
 static void
 bitmap_port_gc_init(struct ip_set *set)
 {
-       struct bitmap_port_timeout *map = set->data;
+       struct bitmap_port *map = set->data;
 
        init_timer(&map->gc);
        map->gc.data = (unsigned long) set;
@@ -535,22 +409,16 @@ bitmap_port_gc_init(struct ip_set *set)
 
 /* Create bitmap:ip type of sets */
 
-static const struct nla_policy
-bitmap_port_create_policy[IPSET_ATTR_CREATE_MAX+1] = {
-       [IPSET_ATTR_PORT]       = { .type = NLA_U16 },
-       [IPSET_ATTR_PORT_TO]    = { .type = NLA_U16 },
-       [IPSET_ATTR_TIMEOUT]    = { .type = NLA_U32 },
-};
-
 static bool
 init_map_port(struct ip_set *set, struct bitmap_port *map,
              u16 first_port, u16 last_port)
 {
-       map->members = ip_set_alloc(map->memsize, GFP_KERNEL);
+       map->members = ip_set_alloc(map->memsize);
        if (!map->members)
                return false;
        map->first_port = first_port;
        map->last_port = last_port;
+       map->timeout = IPSET_NO_TIMEOUT;
 
        set->data = map;
        set->family = AF_UNSPEC;
@@ -559,16 +427,12 @@ init_map_port(struct ip_set *set, struct bitmap_port *map,
 }
 
 static int
-bitmap_port_create(struct ip_set *set, struct nlattr *head, int len,
+bitmap_port_create(struct ip_set *set, struct nlattr *tb[],
                 u32 flags)
 {
-       struct nlattr *tb[IPSET_ATTR_CREATE_MAX+1];
+       struct bitmap_port *map;
        u16 first_port, last_port;
 
-       if (nla_parse(tb, IPSET_ATTR_CREATE_MAX, head, len,
-                     bitmap_port_create_policy))
-               return -IPSET_ERR_PROTOCOL;
-
        if (unlikely(!ip_set_attr_netorder(tb, IPSET_ATTR_PORT) ||
                     !ip_set_attr_netorder(tb, IPSET_ATTR_PORT_TO) ||
                     !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
@@ -583,33 +447,24 @@ bitmap_port_create(struct ip_set *set, struct nlattr *head, int len,
                last_port = tmp;
        }
 
-       if (tb[IPSET_ATTR_TIMEOUT]) {
-               struct bitmap_port_timeout *map;
-
-               map = kzalloc(sizeof(*map), GFP_KERNEL);
-               if (!map)
-                       return -ENOMEM;
+       map = kzalloc(sizeof(*map), GFP_KERNEL);
+       if (!map)
+               return -ENOMEM;
 
+       if (tb[IPSET_ATTR_TIMEOUT]) {
                map->memsize = (last_port - first_port + 1)
                               * sizeof(unsigned long);
 
-               if (!init_map_port(set, (struct bitmap_port *) map,
-                                  first_port, last_port)) {
+               if (!init_map_port(set, map, first_port, last_port)) {
                        kfree(map);
                        return -ENOMEM;
                }
 
                map->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
-               set->variant = &bitmap_port_timeout;
+               set->variant = &bitmap_tport;
 
                bitmap_port_gc_init(set);
        } else {
-               struct bitmap_port *map;
-
-               map = kzalloc(sizeof(*map), GFP_KERNEL);
-               if (!map)
-                       return -ENOMEM;
-
                map->memsize = bitmap_bytes(0, last_port - first_port);
                pr_debug("memsize: %zu\n", map->memsize);
                if (!init_map_port(set, map, first_port, last_port)) {
@@ -630,6 +485,17 @@ static struct ip_set_type bitmap_port_type = {
        .family         = AF_UNSPEC,
        .revision       = 0,
        .create         = bitmap_port_create,
+       .create_policy  = {
+               [IPSET_ATTR_PORT]       = { .type = NLA_U16 },
+               [IPSET_ATTR_PORT_TO]    = { .type = NLA_U16 },
+               [IPSET_ATTR_TIMEOUT]    = { .type = NLA_U32 },
+       },
+       .adt_policy     = {
+               [IPSET_ATTR_PORT]       = { .type = NLA_U16 },
+               [IPSET_ATTR_PORT_TO]    = { .type = NLA_U16 },
+               [IPSET_ATTR_TIMEOUT]    = { .type = NLA_U32 },
+               [IPSET_ATTR_LINENO]     = { .type = NLA_U32 },
+       },
        .me             = THIS_MODULE,
 };
 
index d17cffec16a09871c8c5bcca500687d29ff3cc7b..83da4447e7f7a159ee97ea9c8314d6f242d638ae 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/spinlock.h>
 #include <linux/netlink.h>
 #include <linux/rculist.h>
+#include <linux/version.h>
 #include <net/netlink.h>
 
 #include <linux/netfilter.h>
@@ -196,20 +197,24 @@ EXPORT_SYMBOL_GPL(ip_set_type_unregister);
 
 /* Utility functions */
 void *
-ip_set_alloc(size_t size, gfp_t gfp_mask)
+ip_set_alloc(size_t size)
 {
        void *members = NULL;
 
        if (size < KMALLOC_MAX_SIZE)
-               members = kzalloc(size, gfp_mask | __GFP_NOWARN);
+               members = kzalloc(size, GFP_KERNEL | __GFP_NOWARN);
 
        if (members) {
                pr_debug("%p: allocated with kmalloc\n", members);
                return members;
        }
 
-       members = __vmalloc(size, gfp_mask | __GFP_ZERO | __GFP_HIGHMEM,
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 37)
+       members = __vmalloc(size, GFP_KERNEL | __GFP_ZERO | __GFP_HIGHMEM,
                            PAGE_KERNEL);
+#else
+       members = vzalloc(size);
+#endif
        if (!members)
                return NULL;
        pr_debug("%p: allocated with vmalloc\n", members);
@@ -249,8 +254,7 @@ ip_set_get_ipaddr4(struct nlattr *nla,  __be32 *ipaddr)
 
        if (unlikely(!flag_nested(nla)))
                return -IPSET_ERR_PROTOCOL;
-       if (nla_parse(tb, IPSET_ATTR_IPADDR_MAX, nla_data(nla), nla_len(nla),
-                     ipaddr_policy))
+       if (nla_parse_nested(tb, IPSET_ATTR_IPADDR_MAX, nla, ipaddr_policy))
                return -IPSET_ERR_PROTOCOL;
        if (unlikely(!ip_set_attr_netorder(tb, IPSET_ATTR_IPADDR_IPV4)))
                return -IPSET_ERR_PROTOCOL;
@@ -268,8 +272,7 @@ ip_set_get_ipaddr6(struct nlattr *nla, union nf_inet_addr *ipaddr)
        if (unlikely(!flag_nested(nla)))
                return -IPSET_ERR_PROTOCOL;
 
-       if (nla_parse(tb, IPSET_ATTR_IPADDR_MAX, nla_data(nla), nla_len(nla),
-                     ipaddr_policy))
+       if (nla_parse_nested(tb, IPSET_ATTR_IPADDR_MAX, nla, ipaddr_policy))
                return -IPSET_ERR_PROTOCOL;
        if (unlikely(!ip_set_attr_netorder(tb, IPSET_ATTR_IPADDR_IPV6)))
                return -IPSET_ERR_PROTOCOL;
@@ -611,10 +614,11 @@ ip_set_create(struct sk_buff *skb, struct genl_info *info)
 
        struct ip_set *set, *clash;
        ip_set_id_t index = IPSET_INVALID_ID;
+       struct nlattr *tb[IPSET_ATTR_CREATE_MAX+1] = {};
        const char *name, *typename;
        u8 family, revision;
        u32 flags = flag_exist(info->genlhdr);
-       int ret = 0, len;
+       int ret = 0;
 
        if (unlikely(protocol_failed(attr) ||
                     attr[IPSET_ATTR_SETNAME] == NULL ||
@@ -659,11 +663,14 @@ ip_set_create(struct sk_buff *skb, struct genl_info *info)
        /*
         * Without holding any locks, create private part.
         */
-       len = attr[IPSET_ATTR_DATA] ? nla_len(attr[IPSET_ATTR_DATA]) : 0;
-       pr_debug("data len: %u\n", len);
-       ret = set->type->create(set, attr[IPSET_ATTR_DATA] ?
-                               nla_data(attr[IPSET_ATTR_DATA]) : NULL, len,
-                               flags);
+       if (attr[IPSET_ATTR_DATA] &&
+           nla_parse_nested(tb, IPSET_ATTR_CREATE_MAX, attr[IPSET_ATTR_DATA],
+                            set->type->create_policy)) {
+               ret = -IPSET_ERR_PROTOCOL;
+               goto put_out;
+       }
+
+       ret = set->type->create(set, tb, flags);
        if (ret != 0)
                goto put_out;
 
@@ -749,7 +756,7 @@ ip_set_destroy(struct sk_buff *skb, struct genl_info *info)
        } else {
                i = find_set_id(nla_data(attr[IPSET_ATTR_SETNAME]));
                if (i == IPSET_INVALID_ID)
-                       return -EEXIST;
+                       return -ENOENT;
                else if (atomic_read(&ip_set_list[i]->ref))
                        return -IPSET_ERR_BUSY;
 
@@ -786,7 +793,7 @@ ip_set_flush(struct sk_buff *skb, struct genl_info *info)
        } else {
                i = find_set_id(nla_data(attr[IPSET_ATTR_SETNAME]));
                if (i == IPSET_INVALID_ID)
-                       return -EEXIST;
+                       return -ENOENT;
 
                ip_set_flush_set(ip_set_list[i]);
        }
@@ -820,7 +827,7 @@ ip_set_rename(struct sk_buff *skb, struct genl_info *info)
 
        set = find_set(nla_data(attr[IPSET_ATTR_SETNAME]));
        if (set == NULL)
-               return -EEXIST;
+               return -ENOENT;
        if (atomic_read(&set->ref) != 0)
                return -IPSET_ERR_REFERENCED;
 
@@ -860,7 +867,7 @@ ip_set_swap(struct sk_buff *skb, struct genl_info *info)
 
        from_id = find_set_id(nla_data(attr[IPSET_ATTR_SETNAME]));
        if (from_id == IPSET_INVALID_ID)
-               return -EEXIST;
+               return -ENOENT;
 
        to_id = find_set_id(nla_data(attr[IPSET_ATTR_SETNAME2]));
        if (to_id == IPSET_INVALID_ID)
@@ -946,7 +953,7 @@ dump_init(struct netlink_callback *cb)
 
        index = find_set_id(nla_data(cda[IPSET_ATTR_SETNAME]));
        if (index == IPSET_INVALID_ID)
-               return -EEXIST;
+               return -ENOENT;
 
        cb->args[0] = DUMP_ONE;
        cb->args[1] = index;
@@ -958,16 +965,18 @@ ip_set_dump_start(struct sk_buff *skb, struct netlink_callback *cb)
 {
        ip_set_id_t index = IPSET_INVALID_ID, max;
        struct ip_set *set = NULL;
-       void *nlh = NULL;
+       struct nlmsghdr *nlh = NULL;
        unsigned int flags = NETLINK_CB(cb->skb).pid ? NLM_F_MULTI : 0;
        int ret = 0;
 
        if (cb->args[0] == DUMP_INIT) {
                ret = dump_init(cb);
                if (ret < 0) {
+                       nlh = nlmsg_hdr(cb->skb);
                        /* We have to create and send the error message
                         * manually :-( */
-                       netlink_ack(cb->skb, nlmsg_hdr(cb->skb), ret);
+                       if (nlh->nlmsg_flags & NLM_F_ACK)
+                               netlink_ack(cb->skb, nlh, ret);
                        return ret;
                }
        }
@@ -982,7 +991,7 @@ ip_set_dump_start(struct sk_buff *skb, struct netlink_callback *cb)
                set = ip_set_list[index];
                if (set == NULL) {
                        if (cb->args[0] == DUMP_ONE) {
-                               ret = -EEXIST;
+                               ret = -ENOENT;
                                goto out;
                        }
                        continue;
@@ -1004,7 +1013,7 @@ ip_set_dump_start(struct sk_buff *skb, struct netlink_callback *cb)
                                cb->nlh->nlmsg_seq, flags,
                                IPSET_CMD_LIST);
                if (!nlh) {
-                       ret = -EFAULT;
+                       ret = -EMSGSIZE;
                        goto release_refcount;
                }
                NLA_PUT_U8(skb, IPSET_ATTR_PROTOCOL, IPSET_PROTOCOL);
@@ -1092,19 +1101,17 @@ static const struct nla_policy ip_set_adt_policy[IPSET_ATTR_CMD_MAX + 1] = {
 };
 
 static int
-call_ad(struct sk_buff *skb, struct nlattr *const attr[],
-       struct ip_set *set, const struct nlattr *nla,
-       enum ipset_adt adt, u32 flags)
+call_ad(struct sock *ctnl, struct sk_buff *skb, struct ip_set *set,
+       struct nlattr *tb[], enum ipset_adt adt,
+       u32 flags, bool use_lineno)
 {
-       struct nlattr *head = nla_data(nla);
-       int ret, len = nla_len(nla), retried = 0;
+       int ret, retried = 0;
        u32 lineno = 0;
        bool eexist = flags & IPSET_FLAG_EXIST;
 
        do {
                write_lock_bh(&set->lock);
-               ret = set->variant->uadt(set, head, len, adt,
-                                        &lineno, flags);
+               ret = set->variant->uadt(set, tb, adt, &lineno, flags);
                write_unlock_bh(&set->lock);
        } while (ret == -EAGAIN &&
                 set->variant->resize &&
@@ -1112,11 +1119,38 @@ call_ad(struct sk_buff *skb, struct nlattr *const attr[],
 
        if (!ret || (ret == -IPSET_ERR_EXIST && eexist))
                return 0;
-       if (lineno && attr[IPSET_ATTR_LINENO]) {
+       if (lineno && use_lineno) {
                /* Error in restore/batch mode: send back lineno */
-               u32 *errline = nla_data(attr[IPSET_ATTR_LINENO]);
+               struct nlmsghdr *rep, *nlh = nlmsg_hdr(skb);
+               struct sk_buff *skb2;
+               struct nlmsgerr *errmsg;
+               size_t payload = sizeof(*errmsg) + nlmsg_len(nlh);
+               int min_len = NLMSG_SPACE(sizeof(struct nfgenmsg));
+               struct nlattr *cda[IPSET_ATTR_CMD_MAX+1];
+               struct nlattr *cmdattr;
+               u32 *errline;
+
+               skb2 = nlmsg_new(payload, GFP_KERNEL);
+               if (skb2 == NULL)
+                       return -ENOMEM;
+               rep = __nlmsg_put(skb2, NETLINK_CB(skb).pid,
+                                 nlh->nlmsg_seq, NLMSG_ERROR, payload, 0);
+               errmsg = nlmsg_data(rep);
+               errmsg->error = ret;
+               memcpy(&errmsg->msg, nlh, nlh->nlmsg_len);
+               cmdattr = (void *)&errmsg->msg + min_len;
+
+               nla_parse(cda, IPSET_ATTR_CMD_MAX,
+                         cmdattr, nlh->nlmsg_len - min_len,
+                         ip_set_adt_policy);
+
+               errline = nla_data(cda[IPSET_ATTR_LINENO]);
 
                *errline = lineno;
+
+               netlink_unicast(ctnl, skb2, NETLINK_CB(skb).pid, MSG_DONTWAIT);
+               /* Signal netlink not to send its ACK/errmsg.  */
+               return -EINTR;
        }
 
        return ret;
@@ -1126,10 +1160,13 @@ static int
 ip_set_uadd(struct sk_buff *skb, struct genl_info *info)
 {
        struct nlattr *const *attr = info->attrs;
+       struct sock *ctnl = genl_info_net(info)->genl_sock;
 
        struct ip_set *set;
+       struct nlattr *tb[IPSET_ATTR_ADT_MAX+1] = {};
        const struct nlattr *nla;
        u32 flags = flag_exist(info->genlhdr);
+       bool use_lineno;
        int ret = 0;
 
        if (unlikely(protocol_failed(attr) ||
@@ -1145,20 +1182,28 @@ ip_set_uadd(struct sk_buff *skb, struct genl_info *info)
 
        set = find_set(nla_data(attr[IPSET_ATTR_SETNAME]));
        if (set == NULL)
-               return -EEXIST;
+               return -ENOENT;
 
+       use_lineno = !!attr[IPSET_ATTR_LINENO];
        if (attr[IPSET_ATTR_DATA]) {
-               ret = call_ad(skb, attr,
-                             set, attr[IPSET_ATTR_DATA], IPSET_ADD, flags);
+               if (nla_parse_nested(tb, IPSET_ATTR_ADT_MAX,
+                                    attr[IPSET_ATTR_DATA],
+                                    set->type->adt_policy))
+                       return -IPSET_ERR_PROTOCOL;
+               ret = call_ad(ctnl, skb, set, tb, IPSET_ADD, flags,
+                             use_lineno);
        } else {
                int nla_rem;
 
                nla_for_each_nested(nla, attr[IPSET_ATTR_ADT], nla_rem) {
+                       memset(tb, 0, sizeof(tb));
                        if (nla_type(nla) != IPSET_ATTR_DATA ||
-                           !flag_nested(nla))
+                           !flag_nested(nla) ||
+                           nla_parse_nested(tb, IPSET_ATTR_ADT_MAX, nla,
+                                            set->type->adt_policy))
                                return -IPSET_ERR_PROTOCOL;
-                       ret = call_ad(skb, attr,
-                                      set, nla, IPSET_ADD, flags);
+                       ret = call_ad(ctnl, skb, set, tb, IPSET_ADD,
+                                     flags, use_lineno);
                        if (ret < 0)
                                return ret;
                }
@@ -1170,10 +1215,13 @@ static int
 ip_set_udel(struct sk_buff *skb, struct genl_info *info)
 {
        struct nlattr *const *attr = info->attrs;
+       struct sock *ctnl = genl_info_net(info)->genl_sock;
 
        struct ip_set *set;
+       struct nlattr *tb[IPSET_ATTR_ADT_MAX+1] = {};
        const struct nlattr *nla;
        u32 flags = flag_exist(info->genlhdr);
+       bool use_lineno;
        int ret = 0;
 
        if (unlikely(protocol_failed(attr) ||
@@ -1189,20 +1237,28 @@ ip_set_udel(struct sk_buff *skb, struct genl_info *info)
 
        set = find_set(nla_data(attr[IPSET_ATTR_SETNAME]));
        if (set == NULL)
-               return -EEXIST;
+               return -ENOENT;
 
+       use_lineno = !!attr[IPSET_ATTR_LINENO];
        if (attr[IPSET_ATTR_DATA]) {
-               ret = call_ad(skb, attr,
-                             set, attr[IPSET_ATTR_DATA], IPSET_DEL, flags);
+               if (nla_parse_nested(tb, IPSET_ATTR_ADT_MAX,
+                                    attr[IPSET_ATTR_DATA],
+                                    set->type->adt_policy))
+                       return -IPSET_ERR_PROTOCOL;
+               ret = call_ad(ctnl, skb, set, tb, IPSET_DEL, flags,
+                             use_lineno);
        } else {
                int nla_rem;
 
                nla_for_each_nested(nla, attr[IPSET_ATTR_ADT], nla_rem) {
+                       memset(tb, 0, sizeof(*tb));
                        if (nla_type(nla) != IPSET_ATTR_DATA ||
-                           !flag_nested(nla))
+                           !flag_nested(nla) ||
+                           nla_parse_nested(tb, IPSET_ATTR_ADT_MAX, nla,
+                                            set->type->adt_policy))
                                return -IPSET_ERR_PROTOCOL;
-                       ret = call_ad(skb, attr,
-                                      set, nla, IPSET_DEL, flags);
+                       ret = call_ad(ctnl, skb, set, tb, IPSET_DEL,
+                                     flags, use_lineno);
                        if (ret < 0)
                                return ret;
                }
@@ -1216,6 +1272,7 @@ ip_set_utest(struct sk_buff *skb, struct genl_info *info)
        struct nlattr *const *attr = info->attrs;
 
        struct ip_set *set;
+       struct nlattr *tb[IPSET_ATTR_ADT_MAX+1] = {};
        int ret = 0;
 
        if (unlikely(protocol_failed(attr) ||
@@ -1226,13 +1283,14 @@ ip_set_utest(struct sk_buff *skb, struct genl_info *info)
 
        set = find_set(nla_data(attr[IPSET_ATTR_SETNAME]));
        if (set == NULL)
-               return -EEXIST;
+               return -ENOENT;
+
+       if (nla_parse_nested(tb, IPSET_ATTR_ADT_MAX, attr[IPSET_ATTR_DATA],
+                            set->type->adt_policy))
+               return -IPSET_ERR_PROTOCOL;
 
        read_lock_bh(&set->lock);
-       ret = set->variant->uadt(set,
-                                nla_data(attr[IPSET_ATTR_DATA]),
-                                nla_len(attr[IPSET_ATTR_DATA]),
-                                IPSET_TEST, NULL, 0);
+       ret = set->variant->uadt(set, tb, IPSET_TEST, NULL, 0);
        read_unlock_bh(&set->lock);
        /* Userspace can't trigger element to be re-added */
        if (ret == -EAGAIN)
@@ -1260,7 +1318,7 @@ ip_set_header(struct sk_buff *skb, struct genl_info *info)
 
        index = find_set_id(nla_data(attr[IPSET_ATTR_SETNAME]));
        if (index == IPSET_INVALID_ID)
-               return -EEXIST;
+               return -ENOENT;
        set = ip_set_list[index];
 
        skb2 = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
@@ -1280,7 +1338,7 @@ ip_set_header(struct sk_buff *skb, struct genl_info *info)
 
        ret = genlmsg_unicast(genl_info_net(info), skb2, NETLINK_CB(skb).pid);
        if (ret < 0)
-               return -EFAULT;
+               return ret;
 
        return 0;
 
@@ -1288,7 +1346,7 @@ nla_put_failure:
        nlmsg_cancel(skb2, nlh2);
 nlmsg_failure:
        kfree_skb(skb2);
-       return -EFAULT;
+       return -EMSGSIZE;
 }
 
 /* Get type data */
@@ -1341,7 +1399,7 @@ ip_set_type(struct sk_buff *skb, struct genl_info *info)
        pr_debug("Send TYPE, nlmsg_len: %u\n", skb2->len);
        ret = genlmsg_unicast(genl_info_net(info), skb2, NETLINK_CB(skb).pid);
        if (ret < 0)
-               return -EFAULT;
+               return ret;
 
        return 0;
 
@@ -1349,7 +1407,7 @@ nla_put_failure:
        genlmsg_cancel(skb2, nlh2);
 nlmsg_failure:
        kfree_skb(skb2);
-       return -EFAULT;
+       return -EMSGSIZE;
 }
 
 /* Get protocol version */
@@ -1385,7 +1443,7 @@ ip_set_protocol(struct sk_buff *skb, struct genl_info *info)
 
        ret = genlmsg_unicast(genl_info_net(info), skb2, NETLINK_CB(skb).pid);
        if (ret < 0)
-               return -EFAULT;
+               return ret;
 
        return 0;
 
@@ -1393,7 +1451,7 @@ nla_put_failure:
        genlmsg_cancel(skb2, nlh2);
 nlmsg_failure:
        kfree_skb(skb2);
-       return -EFAULT;
+       return -EMSGSIZE;
 }
 
 static struct genl_ops ip_set_netlink_subsys_cb[] __read_mostly = {
index d6cf5d2c61eb6b9e5443de30ff2615f013c140d6..0daf5e541155c36f6245b62ed04653ed44a0aa3e 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/icmpv6.h>
 #include <linux/netfilter_ipv6/ip6_tables.h>
 #include <net/ip.h>
+#include <net/ipv6.h>
 
 #include "ip_set_getport.h"
 
@@ -93,21 +94,23 @@ ip_set_get_ip4_port(const struct sk_buff *skb, bool src,
 }
 EXPORT_SYMBOL_GPL(ip_set_get_ip4_port);
 
+#if defined(CONFIG_IP6_NF_IPTABLES) || defined(CONFIG_IP6_NF_IPTABLES_MODULE)
 bool
 ip_set_get_ip6_port(const struct sk_buff *skb, bool src,
                    __be16 *port, u8 *proto)
 {
-       unsigned int protooff = 0;
-       int protocol;
-       unsigned short fragoff;
+       int protoff;
+       u8 nexthdr;
 
-       protocol = ipv6_find_hdr(skb, &protooff, -1, &fragoff);
-       if (protocol <= 0 || fragoff)
+       nexthdr = ipv6_hdr(skb)->nexthdr;
+       protoff = ipv6_skip_exthdr(skb, sizeof(struct ipv6hdr), &nexthdr);
+       if (protoff < 0)
                return false;
 
-       return get_port(skb, protocol, protooff, src, port, proto);
+       return get_port(skb, nexthdr, protoff, src, port, proto);
 }
 EXPORT_SYMBOL_GPL(ip_set_get_ip6_port);
+#endif
 
 bool
 ip_set_get_ip_port(const struct sk_buff *skb, u8 pf, bool src, __be16 *port)
@@ -118,8 +121,10 @@ ip_set_get_ip_port(const struct sk_buff *skb, u8 pf, bool src, __be16 *port)
        switch (pf) {
        case AF_INET:
                ret = ip_set_get_ip4_port(skb, src, port, &proto);
+               break;
        case AF_INET6:
                ret = ip_set_get_ip6_port(skb, src, port, &proto);
+               break;
        default:
                return false;
        }
index 694c433298b8b261585912b7551fa2a74df7aea5..3882a81a3b3c8547cbf77354b88868586218dc60 100644 (file)
@@ -3,8 +3,18 @@
 
 extern bool ip_set_get_ip4_port(const struct sk_buff *skb, bool src,
                                __be16 *port, u8 *proto);
+
+#if defined(CONFIG_IP6_NF_IPTABLES) || defined(CONFIG_IP6_NF_IPTABLES_MODULE)
 extern bool ip_set_get_ip6_port(const struct sk_buff *skb, bool src,
                                __be16 *port, u8 *proto);
+#else
+static inline bool ip_set_get_ip6_port(const struct sk_buff *skb, bool src,
+                                      __be16 *port, u8 *proto)
+{
+       return false;
+}
+#endif
+
 extern bool ip_set_get_ip_port(const struct sk_buff *skb, u8 pf, bool src,
                                __be16 *port);
 
index 3eaa9109e12c41127fce52064aabb9b0a8b4dd49..5bc3a9a307ec0b02a2942db69aab403ea7b6e35c 100644 (file)
@@ -12,9 +12,6 @@
 #include <linux/ip.h>
 #include <linux/skbuff.h>
 #include <linux/errno.h>
-#include <linux/uaccess.h>
-#include <linux/bitops.h>
-#include <linux/spinlock.h>
 #include <linux/random.h>
 #include <net/ip.h>
 #include <net/ipv6.h>
@@ -127,29 +124,16 @@ hash_ip4_kadt(struct ip_set *set, const struct sk_buff *skb,
        return adtfn(set, &ip, h->timeout);
 }
 
-static const struct nla_policy hash_ip4_adt_policy[IPSET_ATTR_ADT_MAX + 1] = {
-       [IPSET_ATTR_IP]         = { .type = NLA_NESTED },
-       [IPSET_ATTR_IP_TO]      = { .type = NLA_NESTED },
-       [IPSET_ATTR_CIDR]       = { .type = NLA_U8 },
-       [IPSET_ATTR_TIMEOUT]    = { .type = NLA_U32 },
-       [IPSET_ATTR_LINENO]     = { .type = NLA_U32 },
-};
-
 static int
-hash_ip4_uadt(struct ip_set *set, struct nlattr *head, int len,
+hash_ip4_uadt(struct ip_set *set, struct nlattr *tb[],
              enum ipset_adt adt, u32 *lineno, u32 flags)
 {
        const struct ip_set_hash *h = set->data;
-       struct nlattr *tb[IPSET_ATTR_ADT_MAX+1];
        ipset_adtfn adtfn = set->variant->adt[adt];
        u32 ip, ip_to, hosts, timeout = h->timeout;
        __be32 nip;
        int ret = 0;
 
-       if (nla_parse(tb, IPSET_ATTR_ADT_MAX, head, len,
-                     hash_ip4_adt_policy))
-               return -IPSET_ERR_PROTOCOL;
-
        if (unlikely(!tb[IPSET_ATTR_IP] ||
                     !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
                return -IPSET_ERR_PROTOCOL;
@@ -320,22 +304,19 @@ static const struct nla_policy hash_ip6_adt_policy[IPSET_ATTR_ADT_MAX + 1] = {
 };
 
 static int
-hash_ip6_uadt(struct ip_set *set, struct nlattr *head, int len,
+hash_ip6_uadt(struct ip_set *set, struct nlattr *tb[],
              enum ipset_adt adt, u32 *lineno, u32 flags)
 {
        const struct ip_set_hash *h = set->data;
-       struct nlattr *tb[IPSET_ATTR_ADT_MAX+1];
        ipset_adtfn adtfn = set->variant->adt[adt];
        union nf_inet_addr ip;
        u32 timeout = h->timeout;
        int ret;
 
-       if (nla_parse(tb, IPSET_ATTR_ADT_MAX, head, len,
-                     hash_ip6_adt_policy))
-               return -IPSET_ERR_PROTOCOL;
-
        if (unlikely(!tb[IPSET_ATTR_IP] ||
-                    !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
+                    !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) ||
+                    tb[IPSET_ATTR_IP_TO] ||
+                    tb[IPSET_ATTR_CIDR]))
                return -IPSET_ERR_PROTOCOL;
 
        if (tb[IPSET_ATTR_LINENO])
@@ -362,20 +343,9 @@ hash_ip6_uadt(struct ip_set *set, struct nlattr *head, int len,
 
 /* Create hash:ip type of sets */
 
-static const struct nla_policy
-hash_ip_create_policy[IPSET_ATTR_CREATE_MAX+1] = {
-       [IPSET_ATTR_HASHSIZE]   = { .type = NLA_U32 },
-       [IPSET_ATTR_MAXELEM]    = { .type = NLA_U32 },
-       [IPSET_ATTR_PROBES]     = { .type = NLA_U8 },
-       [IPSET_ATTR_RESIZE]     = { .type = NLA_U8  },
-       [IPSET_ATTR_TIMEOUT]    = { .type = NLA_U32 },
-       [IPSET_ATTR_NETMASK]    = { .type = NLA_U8  },
-};
-
 static int
-hash_ip_create(struct ip_set *set, struct nlattr *head, int len, u32 flags)
+hash_ip_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
 {
-       struct nlattr *tb[IPSET_ATTR_CREATE_MAX+1];
        u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM;
        u8 netmask, hbits;
        struct ip_set_hash *h;
@@ -386,10 +356,6 @@ hash_ip_create(struct ip_set *set, struct nlattr *head, int len, u32 flags)
        pr_debug("Create set %s with family %s\n",
                 set->name, set->family == AF_INET ? "inet" : "inet6");
 
-       if (nla_parse(tb, IPSET_ATTR_CREATE_MAX, head, len,
-                     hash_ip_create_policy))
-               return -IPSET_ERR_PROTOCOL;
-
        if (unlikely(!ip_set_optattr_netorder(tb, IPSET_ATTR_HASHSIZE) ||
                     !ip_set_optattr_netorder(tb, IPSET_ATTR_MAXELEM) ||
                     !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
@@ -425,8 +391,7 @@ hash_ip_create(struct ip_set *set, struct nlattr *head, int len, u32 flags)
        hbits = htable_bits(hashsize);
        h->table = ip_set_alloc(
                        sizeof(struct htable)
-                       + jhash_size(hbits) * sizeof(struct hbucket),
-                       GFP_KERNEL);
+                       + jhash_size(hbits) * sizeof(struct hbucket));
        if (!h->table) {
                kfree(h);
                return -ENOMEM;
@@ -465,6 +430,21 @@ static struct ip_set_type hash_ip_type __read_mostly = {
        .family         = AF_UNSPEC,
        .revision       = 0,
        .create         = hash_ip_create,
+       .create_policy  = {
+               [IPSET_ATTR_HASHSIZE]   = { .type = NLA_U32 },
+               [IPSET_ATTR_MAXELEM]    = { .type = NLA_U32 },
+               [IPSET_ATTR_PROBES]     = { .type = NLA_U8 },
+               [IPSET_ATTR_RESIZE]     = { .type = NLA_U8  },
+               [IPSET_ATTR_TIMEOUT]    = { .type = NLA_U32 },
+               [IPSET_ATTR_NETMASK]    = { .type = NLA_U8  },
+       },
+       .adt_policy     = {
+               [IPSET_ATTR_IP]         = { .type = NLA_NESTED },
+               [IPSET_ATTR_IP_TO]      = { .type = NLA_NESTED },
+               [IPSET_ATTR_CIDR]       = { .type = NLA_U8 },
+               [IPSET_ATTR_TIMEOUT]    = { .type = NLA_U32 },
+               [IPSET_ATTR_LINENO]     = { .type = NLA_U32 },
+       },
        .me             = THIS_MODULE,
 };
 
index 0ffc9fb0251e507b3e4f1cfdd1b9ec06353a3651..a2530e646f9c05626f2f3b5a716c788ff12830f4 100644 (file)
@@ -12,9 +12,6 @@
 #include <linux/ip.h>
 #include <linux/skbuff.h>
 #include <linux/errno.h>
-#include <linux/uaccess.h>
-#include <linux/bitops.h>
-#include <linux/spinlock.h>
 #include <linux/random.h>
 #include <net/ip.h>
 #include <net/ipv6.h>
@@ -144,34 +141,17 @@ hash_ipport4_kadt(struct ip_set *set, const struct sk_buff *skb,
        return adtfn(set, &data, h->timeout);
 }
 
-static const struct nla_policy
-hash_ipport_adt_policy[IPSET_ATTR_ADT_MAX + 1] = {
-       [IPSET_ATTR_IP]         = { .type = NLA_NESTED },
-       [IPSET_ATTR_IP_TO]      = { .type = NLA_NESTED },
-       [IPSET_ATTR_PORT]       = { .type = NLA_U16 },
-       [IPSET_ATTR_PORT_TO]    = { .type = NLA_U16 },
-       [IPSET_ATTR_CIDR]       = { .type = NLA_U8 },
-       [IPSET_ATTR_PROTO]      = { .type = NLA_U8 },
-       [IPSET_ATTR_TIMEOUT]    = { .type = NLA_U32 },
-       [IPSET_ATTR_LINENO]     = { .type = NLA_U32 },
-};
-
 static int
-hash_ipport4_uadt(struct ip_set *set, struct nlattr *head, int len,
+hash_ipport4_uadt(struct ip_set *set, struct nlattr *tb[],
                  enum ipset_adt adt, u32 *lineno, u32 flags)
 {
        const struct ip_set_hash *h = set->data;
-       struct nlattr *tb[IPSET_ATTR_ADT_MAX+1];
        ipset_adtfn adtfn = set->variant->adt[adt];
        struct hash_ipport4_elem data = { };
        u32 ip, ip_to, p, port, port_to;
        u32 timeout = h->timeout;
        int ret;
 
-       if (nla_parse(tb, IPSET_ATTR_ADT_MAX, head, len,
-                     hash_ipport_adt_policy))
-               return -IPSET_ERR_PROTOCOL;
-
        if (unlikely(!tb[IPSET_ATTR_IP] ||
                     !ip_set_attr_netorder(tb, IPSET_ATTR_PORT) ||
                     !ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO) ||
@@ -373,25 +353,22 @@ hash_ipport6_kadt(struct ip_set *set, const struct sk_buff *skb,
 }
 
 static int
-hash_ipport6_uadt(struct ip_set *set, struct nlattr *head, int len,
+hash_ipport6_uadt(struct ip_set *set, struct nlattr *tb[],
                  enum ipset_adt adt, u32 *lineno, u32 flags)
 {
        const struct ip_set_hash *h = set->data;
-       struct nlattr *tb[IPSET_ATTR_ADT_MAX+1];
        ipset_adtfn adtfn = set->variant->adt[adt];
        struct hash_ipport6_elem data = { };
        u32 port, port_to;
        u32 timeout = h->timeout;
        int ret;
 
-       if (nla_parse(tb, IPSET_ATTR_ADT_MAX, head, len,
-                     hash_ipport_adt_policy))
-               return -IPSET_ERR_PROTOCOL;
-
        if (unlikely(!tb[IPSET_ATTR_IP] ||
                     !ip_set_attr_netorder(tb, IPSET_ATTR_PORT) ||
                     !ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO) ||
-                    !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
+                    !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) ||
+                    tb[IPSET_ATTR_IP_TO] ||
+                    tb[IPSET_ATTR_CIDR]))
                return -IPSET_ERR_PROTOCOL;
 
        if (tb[IPSET_ATTR_LINENO])
@@ -456,20 +433,9 @@ hash_ipport6_uadt(struct ip_set *set, struct nlattr *head, int len,
 
 /* Create hash:ip type of sets */
 
-static const struct nla_policy
-hash_ipport_create_policy[IPSET_ATTR_CREATE_MAX+1] = {
-       [IPSET_ATTR_HASHSIZE]   = { .type = NLA_U32 },
-       [IPSET_ATTR_MAXELEM]    = { .type = NLA_U32 },
-       [IPSET_ATTR_PROBES]     = { .type = NLA_U8 },
-       [IPSET_ATTR_RESIZE]     = { .type = NLA_U8  },
-       [IPSET_ATTR_PROTO]      = { .type = NLA_U8 },
-       [IPSET_ATTR_TIMEOUT]    = { .type = NLA_U32 },
-};
-
 static int
-hash_ipport_create(struct ip_set *set, struct nlattr *head, int len, u32 flags)
+hash_ipport_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
 {
-       struct nlattr *tb[IPSET_ATTR_CREATE_MAX+1];
        struct ip_set_hash *h;
        u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM;
        u8 hbits;
@@ -477,10 +443,6 @@ hash_ipport_create(struct ip_set *set, struct nlattr *head, int len, u32 flags)
        if (!(set->family == AF_INET || set->family == AF_INET6))
                return -IPSET_ERR_INVALID_FAMILY;
 
-       if (nla_parse(tb, IPSET_ATTR_CREATE_MAX, head, len,
-                     hash_ipport_create_policy))
-               return -IPSET_ERR_PROTOCOL;
-
        if (unlikely(!ip_set_optattr_netorder(tb, IPSET_ATTR_HASHSIZE) ||
                     !ip_set_optattr_netorder(tb, IPSET_ATTR_MAXELEM) ||
                     !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
@@ -506,8 +468,7 @@ hash_ipport_create(struct ip_set *set, struct nlattr *head, int len, u32 flags)
        hbits = htable_bits(hashsize);
        h->table = ip_set_alloc(
                        sizeof(struct htable)
-                       + jhash_size(hbits) * sizeof(struct hbucket),
-                       GFP_KERNEL);
+                       + jhash_size(hbits) * sizeof(struct hbucket));
        if (!h->table) {
                kfree(h);
                return -ENOMEM;
@@ -546,6 +507,24 @@ static struct ip_set_type hash_ipport_type __read_mostly = {
        .family         = AF_UNSPEC,
        .revision       = 0,
        .create         = hash_ipport_create,
+       .create_policy  = {
+               [IPSET_ATTR_HASHSIZE]   = { .type = NLA_U32 },
+               [IPSET_ATTR_MAXELEM]    = { .type = NLA_U32 },
+               [IPSET_ATTR_PROBES]     = { .type = NLA_U8 },
+               [IPSET_ATTR_RESIZE]     = { .type = NLA_U8  },
+               [IPSET_ATTR_PROTO]      = { .type = NLA_U8 },
+               [IPSET_ATTR_TIMEOUT]    = { .type = NLA_U32 },
+       },
+       .adt_policy     = {
+               [IPSET_ATTR_IP]         = { .type = NLA_NESTED },
+               [IPSET_ATTR_IP_TO]      = { .type = NLA_NESTED },
+               [IPSET_ATTR_PORT]       = { .type = NLA_U16 },
+               [IPSET_ATTR_PORT_TO]    = { .type = NLA_U16 },
+               [IPSET_ATTR_CIDR]       = { .type = NLA_U8 },
+               [IPSET_ATTR_PROTO]      = { .type = NLA_U8 },
+               [IPSET_ATTR_TIMEOUT]    = { .type = NLA_U32 },
+               [IPSET_ATTR_LINENO]     = { .type = NLA_U32 },
+       },
        .me             = THIS_MODULE,
 };
 
index 506377577a9d4f337e656645e04edd392fac217e..a6d17971818e3028779ed1eafe745e9bb976c1a1 100644 (file)
@@ -12,9 +12,6 @@
 #include <linux/ip.h>
 #include <linux/skbuff.h>
 #include <linux/errno.h>
-#include <linux/uaccess.h>
-#include <linux/bitops.h>
-#include <linux/spinlock.h>
 #include <linux/random.h>
 #include <net/ip.h>
 #include <net/ipv6.h>
@@ -148,35 +145,17 @@ hash_ipportip4_kadt(struct ip_set *set, const struct sk_buff *skb,
        return adtfn(set, &data, h->timeout);
 }
 
-static const struct nla_policy
-hash_ipportip_adt_policy[IPSET_ATTR_ADT_MAX + 1] = {
-       [IPSET_ATTR_IP]         = { .type = NLA_NESTED },
-       [IPSET_ATTR_IP_TO]      = { .type = NLA_NESTED },
-       [IPSET_ATTR_IP2]        = { .type = NLA_NESTED },
-       [IPSET_ATTR_PORT]       = { .type = NLA_U16 },
-       [IPSET_ATTR_PORT_TO]    = { .type = NLA_U16 },
-       [IPSET_ATTR_CIDR]       = { .type = NLA_U8 },
-       [IPSET_ATTR_PROTO]      = { .type = NLA_U8 },
-       [IPSET_ATTR_TIMEOUT]    = { .type = NLA_U32 },
-       [IPSET_ATTR_LINENO]     = { .type = NLA_U32 },
-};
-
 static int
-hash_ipportip4_uadt(struct ip_set *set, struct nlattr *head, int len,
+hash_ipportip4_uadt(struct ip_set *set, struct nlattr *tb[],
                    enum ipset_adt adt, u32 *lineno, u32 flags)
 {
        const struct ip_set_hash *h = set->data;
-       struct nlattr *tb[IPSET_ATTR_ADT_MAX+1];
        ipset_adtfn adtfn = set->variant->adt[adt];
        struct hash_ipportip4_elem data = { };
        u32 ip, ip_to, p, port, port_to;
        u32 timeout = h->timeout;
        int ret;
 
-       if (nla_parse(tb, IPSET_ATTR_ADT_MAX, head, len,
-                     hash_ipportip_adt_policy))
-               return -IPSET_ERR_PROTOCOL;
-
        if (unlikely(!tb[IPSET_ATTR_IP] || !tb[IPSET_ATTR_IP2] ||
                     !ip_set_attr_netorder(tb, IPSET_ATTR_PORT) ||
                     !ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO) ||
@@ -388,25 +367,22 @@ hash_ipportip6_kadt(struct ip_set *set, const struct sk_buff *skb,
 }
 
 static int
-hash_ipportip6_uadt(struct ip_set *set, struct nlattr *head, int len,
+hash_ipportip6_uadt(struct ip_set *set, struct nlattr *tb[],
                    enum ipset_adt adt, u32 *lineno, u32 flags)
 {
        const struct ip_set_hash *h = set->data;
-       struct nlattr *tb[IPSET_ATTR_ADT_MAX+1];
        ipset_adtfn adtfn = set->variant->adt[adt];
        struct hash_ipportip6_elem data = { };
        u32 port, port_to;
        u32 timeout = h->timeout;
        int ret;
 
-       if (nla_parse(tb, IPSET_ATTR_ADT_MAX, head, len,
-                     hash_ipportip_adt_policy))
-               return -IPSET_ERR_PROTOCOL;
-
        if (unlikely(!tb[IPSET_ATTR_IP] || !tb[IPSET_ATTR_IP2] ||
                     !ip_set_attr_netorder(tb, IPSET_ATTR_PORT) ||
                     !ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO) ||
-                    !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
+                    !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) ||
+                    tb[IPSET_ATTR_IP_TO] ||
+                    tb[IPSET_ATTR_CIDR]))
                return -IPSET_ERR_PROTOCOL;
 
        if (tb[IPSET_ATTR_LINENO])
@@ -475,20 +451,9 @@ hash_ipportip6_uadt(struct ip_set *set, struct nlattr *head, int len,
 
 /* Create hash:ip type of sets */
 
-static const struct nla_policy
-hash_ipportip_create_policy[IPSET_ATTR_CREATE_MAX+1] = {
-       [IPSET_ATTR_HASHSIZE]   = { .type = NLA_U32 },
-       [IPSET_ATTR_MAXELEM]    = { .type = NLA_U32 },
-       [IPSET_ATTR_PROBES]     = { .type = NLA_U8 },
-       [IPSET_ATTR_RESIZE]     = { .type = NLA_U8  },
-       [IPSET_ATTR_TIMEOUT]    = { .type = NLA_U32 },
-};
-
 static int
-hash_ipportip_create(struct ip_set *set, struct nlattr *head,
-                    int len, u32 flags)
+hash_ipportip_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
 {
-       struct nlattr *tb[IPSET_ATTR_CREATE_MAX+1];
        struct ip_set_hash *h;
        u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM;
        u8 hbits;
@@ -496,10 +461,6 @@ hash_ipportip_create(struct ip_set *set, struct nlattr *head,
        if (!(set->family == AF_INET || set->family == AF_INET6))
                return -IPSET_ERR_INVALID_FAMILY;
 
-       if (nla_parse(tb, IPSET_ATTR_CREATE_MAX, head, len,
-                     hash_ipportip_create_policy))
-               return -IPSET_ERR_PROTOCOL;
-
        if (unlikely(!ip_set_optattr_netorder(tb, IPSET_ATTR_HASHSIZE) ||
                     !ip_set_optattr_netorder(tb, IPSET_ATTR_MAXELEM) ||
                     !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
@@ -525,8 +486,7 @@ hash_ipportip_create(struct ip_set *set, struct nlattr *head,
        hbits = htable_bits(hashsize);
        h->table = ip_set_alloc(
                        sizeof(struct htable)
-                       + jhash_size(hbits) * sizeof(struct hbucket),
-                       GFP_KERNEL);
+                       + jhash_size(hbits) * sizeof(struct hbucket));
        if (!h->table) {
                kfree(h);
                return -ENOMEM;
@@ -565,6 +525,24 @@ static struct ip_set_type hash_ipportip_type __read_mostly = {
        .family         = AF_UNSPEC,
        .revision       = 0,
        .create         = hash_ipportip_create,
+       .create_policy  = {
+               [IPSET_ATTR_HASHSIZE]   = { .type = NLA_U32 },
+               [IPSET_ATTR_MAXELEM]    = { .type = NLA_U32 },
+               [IPSET_ATTR_PROBES]     = { .type = NLA_U8 },
+               [IPSET_ATTR_RESIZE]     = { .type = NLA_U8  },
+               [IPSET_ATTR_TIMEOUT]    = { .type = NLA_U32 },
+       },
+       .adt_policy     = {
+               [IPSET_ATTR_IP]         = { .type = NLA_NESTED },
+               [IPSET_ATTR_IP_TO]      = { .type = NLA_NESTED },
+               [IPSET_ATTR_IP2]        = { .type = NLA_NESTED },
+               [IPSET_ATTR_PORT]       = { .type = NLA_U16 },
+               [IPSET_ATTR_PORT_TO]    = { .type = NLA_U16 },
+               [IPSET_ATTR_CIDR]       = { .type = NLA_U8 },
+               [IPSET_ATTR_PROTO]      = { .type = NLA_U8 },
+               [IPSET_ATTR_TIMEOUT]    = { .type = NLA_U32 },
+               [IPSET_ATTR_LINENO]     = { .type = NLA_U32 },
+       },
        .me             = THIS_MODULE,
 };
 
index 85fa6c744911062b3dde26e3bbc5039f3e5a4ccc..258eeb9b4d5cf9de8cb37a0db58e1eb2c16da267 100644 (file)
@@ -12,9 +12,6 @@
 #include <linux/ip.h>
 #include <linux/skbuff.h>
 #include <linux/errno.h>
-#include <asm/uaccess.h>
-#include <asm/bitops.h>
-#include <linux/spinlock.h>
 #include <linux/random.h>
 #include <net/ip.h>
 #include <net/ipv6.h>
@@ -168,36 +165,17 @@ hash_ipportnet4_kadt(struct ip_set *set, const struct sk_buff *skb,
        return adtfn(set, &data, h->timeout);
 }
 
-static const struct nla_policy
-hash_ipportnet_adt_policy[IPSET_ATTR_ADT_MAX + 1] = {
-       [IPSET_ATTR_IP]         = { .type = NLA_NESTED },
-       [IPSET_ATTR_IP_TO]      = { .type = NLA_NESTED },
-       [IPSET_ATTR_IP2]        = { .type = NLA_NESTED },
-       [IPSET_ATTR_PORT]       = { .type = NLA_U16 },
-       [IPSET_ATTR_PORT_TO]    = { .type = NLA_U16 },
-       [IPSET_ATTR_CIDR]       = { .type = NLA_U8 },
-       [IPSET_ATTR_CIDR2]      = { .type = NLA_U8 },
-       [IPSET_ATTR_PROTO]      = { .type = NLA_U8 },
-       [IPSET_ATTR_TIMEOUT]    = { .type = NLA_U32 },
-       [IPSET_ATTR_LINENO]     = { .type = NLA_U32 },
-};
-
 static int
-hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *head, int len,
+hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[],
                     enum ipset_adt adt, u32 *lineno, u32 flags)
 {
        const struct ip_set_hash *h = set->data;
-       struct nlattr *tb[IPSET_ATTR_ADT_MAX+1];
        ipset_adtfn adtfn = set->variant->adt[adt];
        struct hash_ipportnet4_elem data = { .cidr = HOST_MASK };
        u32 ip, ip_to, p, port, port_to;
        u32 timeout = h->timeout;
        int ret;
 
-       if (nla_parse(tb, IPSET_ATTR_ADT_MAX, head, len,
-                     hash_ipportnet_adt_policy))
-               return -IPSET_ERR_PROTOCOL;
-
        if (unlikely(!tb[IPSET_ATTR_IP] || !tb[IPSET_ATTR_IP2] ||
                     !ip_set_attr_netorder(tb, IPSET_ATTR_PORT) ||
                     !ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO) ||
@@ -443,25 +421,22 @@ hash_ipportnet6_kadt(struct ip_set *set, const struct sk_buff *skb,
 }
 
 static int
-hash_ipportnet6_uadt(struct ip_set *set, struct nlattr *head, int len,
+hash_ipportnet6_uadt(struct ip_set *set, struct nlattr *tb[],
                     enum ipset_adt adt, u32 *lineno, u32 flags)
 {
        const struct ip_set_hash *h = set->data;
-       struct nlattr *tb[IPSET_ATTR_ADT_MAX+1];
        ipset_adtfn adtfn = set->variant->adt[adt];
        struct hash_ipportnet6_elem data = { .cidr = HOST_MASK };
        u32 port, port_to;
        u32 timeout = h->timeout;
        int ret;
 
-       if (nla_parse(tb, IPSET_ATTR_ADT_MAX, head, len,
-                     hash_ipportnet_adt_policy))
-               return -IPSET_ERR_PROTOCOL;
-
        if (unlikely(!tb[IPSET_ATTR_IP] || !tb[IPSET_ATTR_IP2] ||
                     !ip_set_attr_netorder(tb, IPSET_ATTR_PORT) ||
                     !ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO) ||
-                    !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
+                    !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) ||
+                    tb[IPSET_ATTR_IP_TO] ||
+                    tb[IPSET_ATTR_CIDR]))
                return -IPSET_ERR_PROTOCOL;
 
        if (tb[IPSET_ATTR_LINENO])
@@ -538,20 +513,9 @@ hash_ipportnet6_uadt(struct ip_set *set, struct nlattr *head, int len,
 
 /* Create hash:ip type of sets */
 
-static const struct nla_policy
-hash_ipportnet_create_policy[IPSET_ATTR_CREATE_MAX+1] = {
-       [IPSET_ATTR_HASHSIZE]   = { .type = NLA_U32 },
-       [IPSET_ATTR_MAXELEM]    = { .type = NLA_U32 },
-       [IPSET_ATTR_PROBES]     = { .type = NLA_U8 },
-       [IPSET_ATTR_RESIZE]     = { .type = NLA_U8  },
-       [IPSET_ATTR_TIMEOUT]    = { .type = NLA_U32 },
-};
-
 static int
-hash_ipportnet_create(struct ip_set *set, struct nlattr *head,
-                    int len, u32 flags)
+hash_ipportnet_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
 {
-       struct nlattr *tb[IPSET_ATTR_CREATE_MAX+1];
        struct ip_set_hash *h;
        u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM;
        u8 hbits;
@@ -559,10 +523,6 @@ hash_ipportnet_create(struct ip_set *set, struct nlattr *head,
        if (!(set->family == AF_INET || set->family == AF_INET6))
                return -IPSET_ERR_INVALID_FAMILY;
 
-       if (nla_parse(tb, IPSET_ATTR_CREATE_MAX, head, len,
-                     hash_ipportnet_create_policy))
-               return -IPSET_ERR_PROTOCOL;
-
        if (unlikely(!ip_set_optattr_netorder(tb, IPSET_ATTR_HASHSIZE) ||
                     !ip_set_optattr_netorder(tb, IPSET_ATTR_MAXELEM) ||
                     !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
@@ -590,8 +550,7 @@ hash_ipportnet_create(struct ip_set *set, struct nlattr *head,
        hbits = htable_bits(hashsize);
        h->table = ip_set_alloc(
                        sizeof(struct htable)
-                       + jhash_size(hbits) * sizeof(struct hbucket),
-                       GFP_KERNEL);
+                       + jhash_size(hbits) * sizeof(struct hbucket));
        if (!h->table) {
                kfree(h);
                return -ENOMEM;
@@ -631,6 +590,25 @@ static struct ip_set_type hash_ipportnet_type __read_mostly = {
        .family         = AF_UNSPEC,
        .revision       = 0,
        .create         = hash_ipportnet_create,
+       .create_policy  = {
+               [IPSET_ATTR_HASHSIZE]   = { .type = NLA_U32 },
+               [IPSET_ATTR_MAXELEM]    = { .type = NLA_U32 },
+               [IPSET_ATTR_PROBES]     = { .type = NLA_U8 },
+               [IPSET_ATTR_RESIZE]     = { .type = NLA_U8  },
+               [IPSET_ATTR_TIMEOUT]    = { .type = NLA_U32 },
+       },
+       .adt_policy     = {
+               [IPSET_ATTR_IP]         = { .type = NLA_NESTED },
+               [IPSET_ATTR_IP_TO]      = { .type = NLA_NESTED },
+               [IPSET_ATTR_IP2]        = { .type = NLA_NESTED },
+               [IPSET_ATTR_PORT]       = { .type = NLA_U16 },
+               [IPSET_ATTR_PORT_TO]    = { .type = NLA_U16 },
+               [IPSET_ATTR_CIDR]       = { .type = NLA_U8 },
+               [IPSET_ATTR_CIDR2]      = { .type = NLA_U8 },
+               [IPSET_ATTR_PROTO]      = { .type = NLA_U8 },
+               [IPSET_ATTR_TIMEOUT]    = { .type = NLA_U32 },
+               [IPSET_ATTR_LINENO]     = { .type = NLA_U32 },
+       },
        .me             = THIS_MODULE,
 };
 
index 7f01112490b50a03f5d7a2eff47580e108accc14..c5d072264c059e0aa393e8a44963b329eed27326 100644 (file)
@@ -12,9 +12,6 @@
 #include <linux/ip.h>
 #include <linux/skbuff.h>
 #include <linux/errno.h>
-#include <linux/uaccess.h>
-#include <linux/bitops.h>
-#include <linux/spinlock.h>
 #include <linux/random.h>
 #include <net/ip.h>
 #include <net/ipv6.h>
@@ -147,27 +144,16 @@ hash_net4_kadt(struct ip_set *set, const struct sk_buff *skb,
        return adtfn(set, &data, h->timeout);
 }
 
-static const struct nla_policy hash_net_adt_policy[IPSET_ATTR_ADT_MAX + 1] = {
-       [IPSET_ATTR_IP]         = { .type = NLA_NESTED },
-       [IPSET_ATTR_CIDR]       = { .type = NLA_U8 },
-       [IPSET_ATTR_TIMEOUT]    = { .type = NLA_U32 },
-};
-
 static int
-hash_net4_uadt(struct ip_set *set, struct nlattr *head, int len,
+hash_net4_uadt(struct ip_set *set, struct nlattr *tb[],
               enum ipset_adt adt, u32 *lineno, u32 flags)
 {
        const struct ip_set_hash *h = set->data;
-       struct nlattr *tb[IPSET_ATTR_ADT_MAX+1];
        ipset_adtfn adtfn = set->variant->adt[adt];
        struct hash_net4_elem data = { .cidr = HOST_MASK };
        u32 timeout = h->timeout;
        int ret;
 
-       if (nla_parse(tb, IPSET_ATTR_ADT_MAX, head, len,
-                     hash_net_adt_policy))
-               return -IPSET_ERR_PROTOCOL;
-
        if (unlikely(!tb[IPSET_ATTR_IP] ||
                     !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
                return -IPSET_ERR_PROTOCOL;
@@ -324,20 +310,15 @@ hash_net6_kadt(struct ip_set *set, const struct sk_buff *skb,
 }
 
 static int
-hash_net6_uadt(struct ip_set *set, struct nlattr *head, int len,
+hash_net6_uadt(struct ip_set *set, struct nlattr *tb[],
               enum ipset_adt adt, u32 *lineno, u32 flags)
 {
        const struct ip_set_hash *h = set->data;
-       struct nlattr *tb[IPSET_ATTR_ADT_MAX+1];
        ipset_adtfn adtfn = set->variant->adt[adt];
        struct hash_net6_elem data = { .cidr = HOST_MASK };
        u32 timeout = h->timeout;
        int ret;
 
-       if (nla_parse(tb, IPSET_ATTR_ADT_MAX, head, len,
-                     hash_net_adt_policy))
-               return -IPSET_ERR_PROTOCOL;
-
        if (unlikely(!tb[IPSET_ATTR_IP] ||
                     !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
                return -IPSET_ERR_PROTOCOL;
@@ -370,19 +351,9 @@ hash_net6_uadt(struct ip_set *set, struct nlattr *head, int len,
 
 /* Create hash:ip type of sets */
 
-static const struct nla_policy
-hash_net_create_policy[IPSET_ATTR_CREATE_MAX+1] = {
-       [IPSET_ATTR_HASHSIZE]   = { .type = NLA_U32 },
-       [IPSET_ATTR_MAXELEM]    = { .type = NLA_U32 },
-       [IPSET_ATTR_PROBES]     = { .type = NLA_U8 },
-       [IPSET_ATTR_RESIZE]     = { .type = NLA_U8  },
-       [IPSET_ATTR_TIMEOUT]    = { .type = NLA_U32 },
-};
-
 static int
-hash_net_create(struct ip_set *set, struct nlattr *head, int len, u32 flags)
+hash_net_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
 {
-       struct nlattr *tb[IPSET_ATTR_CREATE_MAX+1];
        u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM;
        struct ip_set_hash *h;
        u8 hbits;
@@ -390,10 +361,6 @@ hash_net_create(struct ip_set *set, struct nlattr *head, int len, u32 flags)
        if (!(set->family == AF_INET || set->family == AF_INET6))
                return -IPSET_ERR_INVALID_FAMILY;
 
-       if (nla_parse(tb, IPSET_ATTR_CREATE_MAX, head, len,
-                     hash_net_create_policy))
-               return -IPSET_ERR_PROTOCOL;
-
        if (unlikely(!ip_set_optattr_netorder(tb, IPSET_ATTR_HASHSIZE) ||
                     !ip_set_optattr_netorder(tb, IPSET_ATTR_MAXELEM) ||
                     !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
@@ -421,8 +388,7 @@ hash_net_create(struct ip_set *set, struct nlattr *head, int len, u32 flags)
        hbits = htable_bits(hashsize);
        h->table = ip_set_alloc(
                        sizeof(struct htable)
-                       + jhash_size(hbits) * sizeof(struct hbucket),
-                       GFP_KERNEL);
+                       + jhash_size(hbits) * sizeof(struct hbucket));
        if (!h->table) {
                kfree(h);
                return -ENOMEM;
@@ -461,6 +427,18 @@ static struct ip_set_type hash_net_type __read_mostly = {
        .family         = AF_UNSPEC,
        .revision       = 0,
        .create         = hash_net_create,
+       .create_policy  = {
+               [IPSET_ATTR_HASHSIZE]   = { .type = NLA_U32 },
+               [IPSET_ATTR_MAXELEM]    = { .type = NLA_U32 },
+               [IPSET_ATTR_PROBES]     = { .type = NLA_U8 },
+               [IPSET_ATTR_RESIZE]     = { .type = NLA_U8  },
+               [IPSET_ATTR_TIMEOUT]    = { .type = NLA_U32 },
+       },
+       .adt_policy     = {
+               [IPSET_ATTR_IP]         = { .type = NLA_NESTED },
+               [IPSET_ATTR_CIDR]       = { .type = NLA_U8 },
+               [IPSET_ATTR_TIMEOUT]    = { .type = NLA_U32 },
+       },
        .me             = THIS_MODULE,
 };
 
index 6e86b620b0fc4be3d63fab16f71a5d98d48adf57..249c5b386debc7ad596227e29058fd727022133f 100644 (file)
@@ -12,9 +12,6 @@
 #include <linux/ip.h>
 #include <linux/skbuff.h>
 #include <linux/errno.h>
-#include <linux/uaccess.h>
-#include <linux/bitops.h>
-#include <linux/spinlock.h>
 #include <linux/random.h>
 #include <net/ip.h>
 #include <net/ipv6.h>
@@ -164,33 +161,17 @@ hash_netport4_kadt(struct ip_set *set, const struct sk_buff *skb,
        return adtfn(set, &data, h->timeout);
 }
 
-static const struct nla_policy
-hash_netport_adt_policy[IPSET_ATTR_ADT_MAX + 1] = {
-       [IPSET_ATTR_IP]         = { .type = NLA_NESTED },
-       [IPSET_ATTR_PORT]       = { .type = NLA_U16 },
-       [IPSET_ATTR_PORT_TO]    = { .type = NLA_U16 },
-       [IPSET_ATTR_PROTO]      = { .type = NLA_U8 },
-       [IPSET_ATTR_CIDR]       = { .type = NLA_U8 },
-       [IPSET_ATTR_TIMEOUT]    = { .type = NLA_U32 },
-       [IPSET_ATTR_LINENO]     = { .type = NLA_U32 },
-};
-
 static int
-hash_netport4_uadt(struct ip_set *set, struct nlattr *head, int len,
+hash_netport4_uadt(struct ip_set *set, struct nlattr *tb[],
                   enum ipset_adt adt, u32 *lineno, u32 flags)
 {
        const struct ip_set_hash *h = set->data;
-       struct nlattr *tb[IPSET_ATTR_ADT_MAX+1];
        ipset_adtfn adtfn = set->variant->adt[adt];
        struct hash_netport4_elem data = { .cidr = HOST_MASK };
        u32 port, port_to;
        u32 timeout = h->timeout;
        int ret;
 
-       if (nla_parse(tb, IPSET_ATTR_ADT_MAX, head, len,
-                     hash_netport_adt_policy))
-               return -IPSET_ERR_PROTOCOL;
-
        if (unlikely(!tb[IPSET_ATTR_IP] ||
                     !ip_set_attr_netorder(tb, IPSET_ATTR_PORT) ||
                     !ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO) ||
@@ -401,21 +382,16 @@ hash_netport6_kadt(struct ip_set *set, const struct sk_buff *skb,
 }
 
 static int
-hash_netport6_uadt(struct ip_set *set, struct nlattr *head, int len,
+hash_netport6_uadt(struct ip_set *set, struct nlattr *tb[],
                   enum ipset_adt adt, u32 *lineno, u32 flags)
 {
        const struct ip_set_hash *h = set->data;
-       struct nlattr *tb[IPSET_ATTR_ADT_MAX+1];
        ipset_adtfn adtfn = set->variant->adt[adt];
        struct hash_netport6_elem data = { .cidr = HOST_MASK };
        u32 port, port_to;
        u32 timeout = h->timeout;
        int ret;
 
-       if (nla_parse(tb, IPSET_ATTR_ADT_MAX, head, len,
-                     hash_netport_adt_policy))
-               return -IPSET_ERR_PROTOCOL;
-
        if (unlikely(!tb[IPSET_ATTR_IP] ||
                     !ip_set_attr_netorder(tb, IPSET_ATTR_PORT) ||
                     !ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO) ||
@@ -490,20 +466,9 @@ hash_netport6_uadt(struct ip_set *set, struct nlattr *head, int len,
 
 /* Create hash:ip type of sets */
 
-static const struct nla_policy
-hash_netport_create_policy[IPSET_ATTR_CREATE_MAX+1] = {
-       [IPSET_ATTR_HASHSIZE]   = { .type = NLA_U32 },
-       [IPSET_ATTR_MAXELEM]    = { .type = NLA_U32 },
-       [IPSET_ATTR_PROBES]     = { .type = NLA_U8 },
-       [IPSET_ATTR_RESIZE]     = { .type = NLA_U8  },
-       [IPSET_ATTR_PROTO]      = { .type = NLA_U8 },
-       [IPSET_ATTR_TIMEOUT]    = { .type = NLA_U32 },
-};
-
 static int
-hash_netport_create(struct ip_set *set, struct nlattr *head, int len, u32 flags)
+hash_netport_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
 {
-       struct nlattr *tb[IPSET_ATTR_CREATE_MAX+1];
        struct ip_set_hash *h;
        u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM;
        u8 hbits;
@@ -511,10 +476,6 @@ hash_netport_create(struct ip_set *set, struct nlattr *head, int len, u32 flags)
        if (!(set->family == AF_INET || set->family == AF_INET6))
                return -IPSET_ERR_INVALID_FAMILY;
 
-       if (nla_parse(tb, IPSET_ATTR_CREATE_MAX, head, len,
-                     hash_netport_create_policy))
-               return -IPSET_ERR_PROTOCOL;
-
        if (unlikely(!ip_set_optattr_netorder(tb, IPSET_ATTR_HASHSIZE) ||
                     !ip_set_optattr_netorder(tb, IPSET_ATTR_MAXELEM) ||
                     !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
@@ -542,8 +503,7 @@ hash_netport_create(struct ip_set *set, struct nlattr *head, int len, u32 flags)
        hbits = htable_bits(hashsize);
        h->table = ip_set_alloc(
                        sizeof(struct htable)
-                       + jhash_size(hbits) * sizeof(struct hbucket),
-                       GFP_KERNEL);
+                       + jhash_size(hbits) * sizeof(struct hbucket));
        if (!h->table) {
                kfree(h);
                return -ENOMEM;
@@ -582,6 +542,23 @@ static struct ip_set_type hash_netport_type __read_mostly = {
        .family         = AF_UNSPEC,
        .revision       = 0,
        .create         = hash_netport_create,
+       .create_policy  = {
+               [IPSET_ATTR_HASHSIZE]   = { .type = NLA_U32 },
+               [IPSET_ATTR_MAXELEM]    = { .type = NLA_U32 },
+               [IPSET_ATTR_PROBES]     = { .type = NLA_U8 },
+               [IPSET_ATTR_RESIZE]     = { .type = NLA_U8  },
+               [IPSET_ATTR_PROTO]      = { .type = NLA_U8 },
+               [IPSET_ATTR_TIMEOUT]    = { .type = NLA_U32 },
+       },
+       .adt_policy     = {
+               [IPSET_ATTR_IP]         = { .type = NLA_NESTED },
+               [IPSET_ATTR_PORT]       = { .type = NLA_U16 },
+               [IPSET_ATTR_PORT_TO]    = { .type = NLA_U16 },
+               [IPSET_ATTR_PROTO]      = { .type = NLA_U8 },
+               [IPSET_ATTR_CIDR]       = { .type = NLA_U8 },
+               [IPSET_ATTR_TIMEOUT]    = { .type = NLA_U32 },
+               [IPSET_ATTR_LINENO]     = { .type = NLA_U32 },
+       },
        .me             = THIS_MODULE,
 };
 
index 398adc4fccf14cd117dbcb5169689dd092c20373..7fc98ff3bb658ae5a88584a61431755ae2187772 100644 (file)
@@ -111,16 +111,6 @@ list_set_kadt(struct ip_set *set, const struct sk_buff *skb,
        return -EINVAL;
 }
 
-static const struct nla_policy list_set_adt_policy[IPSET_ATTR_ADT_MAX+1] = {
-       [IPSET_ATTR_NAME]       = { .type = NLA_STRING,
-                                   .len = IPSET_MAXNAMELEN },
-       [IPSET_ATTR_NAMEREF]    = { .type = NLA_STRING,
-                                   .len = IPSET_MAXNAMELEN },
-       [IPSET_ATTR_TIMEOUT]    = { .type = NLA_U32 },
-       [IPSET_ATTR_LINENO]     = { .type = NLA_U32 },
-       [IPSET_ATTR_CADT_FLAGS] = { .type = NLA_U32 },
-};
-
 static bool
 next_id_eq(const struct list_set *map, u32 i, ip_set_id_t id)
 {
@@ -204,11 +194,10 @@ list_set_del(struct list_set *map, ip_set_id_t id, u32 i)
 }
 
 static int
-list_set_uadt(struct ip_set *set, struct nlattr *head, int len,
+list_set_uadt(struct ip_set *set, struct nlattr *tb[],
              enum ipset_adt adt, u32 *lineno, u32 flags)
 {
        struct list_set *map = set->data;
-       struct nlattr *tb[IPSET_ATTR_ADT_MAX+1];
        bool with_timeout = with_timeout(map->timeout);
        int before = 0;
        u32 timeout = map->timeout;
@@ -218,10 +207,6 @@ list_set_uadt(struct ip_set *set, struct nlattr *head, int len,
        u32 i;
        int ret = 0;
 
-       if (nla_parse(tb, IPSET_ATTR_ADT_MAX, head, len,
-                     list_set_adt_policy))
-               return -IPSET_ERR_PROTOCOL;
-
        if (unlikely(!tb[IPSET_ATTR_NAME] ||
                     !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) ||
                     !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS)))
@@ -392,7 +377,7 @@ list_set_head(struct ip_set *set, struct sk_buff *skb)
 
        return 0;
 nla_put_failure:
-       return -EFAULT;
+       return -EMSGSIZE;
 }
 
 static int
@@ -406,7 +391,7 @@ list_set_list(const struct ip_set *set,
 
        atd = ipset_nest_start(skb, IPSET_ATTR_ADT);
        if (!atd)
-               return -EFAULT;
+               return -EMSGSIZE;
        for (; cb->args[2] < map->size; cb->args[2]++) {
                i = cb->args[2];
                e = list_set_elem(map, i);
@@ -418,7 +403,7 @@ list_set_list(const struct ip_set *set,
                if (!nested) {
                        if (i == first) {
                                nla_nest_cancel(skb, atd);
-                               return -EFAULT;
+                               return -EMSGSIZE;
                        } else
                                goto nla_put_failure;
                }
@@ -441,6 +426,10 @@ finish:
 nla_put_failure:
        nla_nest_cancel(skb, nested);
        ipset_nest_end(skb, atd);
+       if (unlikely(i == first)) {
+               cb->args[2] = 0;
+               return -EMSGSIZE;
+       }
        return 0;
 }
 
@@ -501,12 +490,6 @@ list_set_gc_init(struct ip_set *set)
 
 /* Create list:set type of sets */
 
-static const struct nla_policy
-list_set_create_policy[IPSET_ATTR_CREATE_MAX+1] = {
-       [IPSET_ATTR_SIZE]       = { .type = NLA_U32 },
-       [IPSET_ATTR_TIMEOUT]    = { .type = NLA_U32 },
-};
-
 static bool
 init_list_set(struct ip_set *set, u32 size, size_t dsize,
              unsigned long timeout)
@@ -533,16 +516,10 @@ init_list_set(struct ip_set *set, u32 size, size_t dsize,
 }
 
 static int
-list_set_create(struct ip_set *set, struct nlattr *head, int len,
-               u32 flags)
+list_set_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
 {
-       struct nlattr *tb[IPSET_ATTR_CREATE_MAX+1];
        u32 size = IP_SET_LIST_DEFAULT_SIZE;
 
-       if (nla_parse(tb, IPSET_ATTR_CREATE_MAX, head, len,
-                     list_set_create_policy))
-               return -IPSET_ERR_PROTOCOL;
-
        if (unlikely(!ip_set_optattr_netorder(tb, IPSET_ATTR_SIZE) ||
                     !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
                return -IPSET_ERR_PROTOCOL;
@@ -575,6 +552,19 @@ static struct ip_set_type list_set_type __read_mostly = {
        .family         = AF_UNSPEC,
        .revision       = 0,
        .create         = list_set_create,
+       .create_policy  = {
+               [IPSET_ATTR_SIZE]       = { .type = NLA_U32 },
+               [IPSET_ATTR_TIMEOUT]    = { .type = NLA_U32 },
+       },
+       .adt_policy     = {
+               [IPSET_ATTR_NAME]       = { .type = NLA_STRING,
+                                           .len = IPSET_MAXNAMELEN },
+               [IPSET_ATTR_NAMEREF]    = { .type = NLA_STRING,
+                                           .len = IPSET_MAXNAMELEN },
+               [IPSET_ATTR_TIMEOUT]    = { .type = NLA_U32 },
+               [IPSET_ATTR_LINENO]     = { .type = NLA_U32 },
+               [IPSET_ATTR_CADT_FLAGS] = { .type = NLA_U32 },
+       },
        .me             = THIS_MODULE,
 };
 
index 9d1b6306dcaff60ed2d0456f6179f9cb08587723..91a5ee406bd295f2424b08147dc7aa8fcd2558ca 100644 (file)
@@ -43,8 +43,8 @@ static const uint16_t cmdflags[] = {
        [IPSET_CMD_FLUSH-1]     = NLM_F_REQUEST|NLM_F_ACK,
        [IPSET_CMD_RENAME-1]    = NLM_F_REQUEST|NLM_F_ACK,
        [IPSET_CMD_SWAP-1]      = NLM_F_REQUEST|NLM_F_ACK,
-       [IPSET_CMD_LIST-1]      = NLM_F_REQUEST,
-       [IPSET_CMD_SAVE-1]      = NLM_F_REQUEST,
+       [IPSET_CMD_LIST-1]      = NLM_F_REQUEST|NLM_F_ACK,
+       [IPSET_CMD_SAVE-1]      = NLM_F_REQUEST|NLM_F_ACK,
        [IPSET_CMD_ADD-1]       = NLM_F_REQUEST|NLM_F_ACK|NLM_F_EXCL,
        [IPSET_CMD_DEL-1]       = NLM_F_REQUEST|NLM_F_ACK|NLM_F_EXCL,
        [IPSET_CMD_TEST-1]      = NLM_F_REQUEST|NLM_F_ACK,
@@ -83,7 +83,7 @@ ipset_mnl_fill_hdr(struct ipset_handle *handle, enum ipset_cmd cmd,
        nlh->nlmsg_flags = NLM_F_REQUEST;
        if (cmdflags[cmd-1] & NLM_F_ACK)
                nlh->nlmsg_flags |= NLM_F_ACK;
-       nlh->nlmsg_seq = handle->seq = time(NULL);
+       nlh->nlmsg_seq = ++handle->seq;
 
        ghdr = mnl_nlmsg_put_extra_header(nlh, sizeof(struct genlmsghdr));
        ghdr->cmd = cmd;
@@ -225,6 +225,7 @@ ipset_mnl_init(mnl_cb_t *cb_ctl, void *data)
        handle->portid = mnl_socket_get_portid(handle->h);
        handle->cb_ctl = cb_ctl;
        handle->data = data;
+       handle->seq = time(NULL);
        
        if (ipset_mnl_getid(handle, false) < 0)
                goto close_nl;
index e998df598d27052e7672ee28dd43497aca1fc30e..cd1ad321a22c6469ff3ae7c603d5ba3fcd368d35 100644 (file)
@@ -1416,15 +1416,14 @@ ipset_parse_ignored(struct ipset_session *session,
  */
 int
 ipset_call_parser(struct ipset_session *session,
-                 ipset_parsefn parse, const char *optstr,
-                 enum ipset_opt opt, const char *str)
+                                 const struct ipset_arg *arg,
+                                 const char *str)
 {
        if (ipset_data_flags_test(ipset_session_data(session),
-                                 IPSET_FLAG(opt)))
-               syntax_err("%s already specified", optstr);
+                                 IPSET_FLAG(arg->opt)))
+               syntax_err("%s already specified", arg->name[0]);
 
-       return parse(session, opt, parse == ipset_parse_ignored
-                                  ? optstr : str);
+       return arg->parse(session, arg->opt, str);
 }
 
 #define parse_elem(s, t, d, str)                                       \
index 7ec786f6b8f3528fd99d2c213385bbc56206aaaf..5284b0ab188c4f60d04453d2d3ece10ea9761e95 100644 (file)
@@ -158,7 +158,8 @@ __getnameinfo##f(char *buf, unsigned int len,                               \
                          sizeof(saddr),                                \
                          buf, len, NULL, 0, flags);                    \
                                                                        \
-       if (err == EAI_AGAIN && !(flags & NI_NUMERICHOST))              \
+       if (!(flags & NI_NUMERICHOST) &&                                \
+           (err == EAI_AGAIN || (err == 0 && strchr(buf, '-') != NULL))) \
                err = getnameinfo((const struct sockaddr *)&saddr,      \
                                  sizeof(saddr),                        \
                                  buf, len, NULL, 0,                    \
@@ -229,7 +230,7 @@ ipset_print_ip(char *buf, unsigned int len,
                D("CIDR: %u", cidr);
        } else
                cidr = family == AF_INET6 ? 128 : 32;
-       flags = env & (1 << IPSET_ENV_RESOLVE) ? 0 : NI_NUMERICHOST;
+       flags = (env & IPSET_ENV_RESOLVE) ? 0 : NI_NUMERICHOST;
        
        ip = ipset_data_get(data, opt);
        assert(ip);
@@ -296,7 +297,7 @@ ipset_print_ipaddr(char *buf, unsigned int len,
                cidr = *(const uint8_t *) ipset_data_get(data, cidropt);
        else
                cidr = family == AF_INET6 ? 128 : 32;
-       flags = env & (1 << IPSET_ENV_RESOLVE) ? 0 : NI_NUMERICHOST;
+       flags = (env & IPSET_ENV_RESOLVE) ? 0 : NI_NUMERICHOST;
 
        ip = ipset_data_get(data, opt);
        assert(ip);
index 69dac6aa3491543087668dccbf4ea05704cea869..5eb53c4f58755d0bf3fb9f01cf8f169195d8b22f 100644 (file)
@@ -441,13 +441,15 @@ ipset_type_add(struct ipset_type *type)
 
        assert(type);
 
+       if (strlen(type->name) > IPSET_MAXNAMELEN - 1)
+               return -EINVAL;
+
        /* Add to the list: higher revision numbers first */
        for (t = typelist, prev = NULL; t != NULL; t = t->next) {
                if (STREQ(t->name, type->name)) {
-                       if (t->revision == type->revision) {
-                               errno = EEXIST;
-                               return -1;
-                       } else if (t->revision < type->revision) {
+                       if (t->revision == type->revision)
+                               return -EEXIST;
+                       else if (t->revision < type->revision) {
                                type->next = t;
                                if (prev)
                                        prev->next = type;
@@ -457,10 +459,9 @@ ipset_type_add(struct ipset_type *type)
                        }
                }
                if (t->next != NULL && STREQ(t->next->name, type->name)) {
-                       if (t->next->revision == type->revision) {
-                               errno = EEXIST;
-                               return -1;
-                       } else if (t->next->revision < type->revision) {
+                       if (t->next->revision == type->revision)
+                               return -EEXIST;
+                       else if (t->next->revision < type->revision) {
                                type->next = t->next;
                                t->next = type;
                                return 0;
index 313c5002f733c4f8c11eda3d0e44f8dce2c34435..6370ec7f365cc919b43c4f096e2ebd40a64baa70 100644 (file)
 /* Core kernel error codes */
 static const struct ipset_errcode_table core_errcode_table[] = {
        /* Generic error codes */
-       { EEXIST, 0,
+       { ENOENT, 0,
          "The set with the given name does not exist" },
+       { EMSGSIZE, 0,
+         "Kernel error received: message could not be created" },
        { IPSET_ERR_PROTOCOL,  0,
          "Kernel error received: ipset protocol error" },
 
@@ -30,14 +32,14 @@ static const struct ipset_errcode_table core_errcode_table[] = {
        { EEXIST, IPSET_CMD_CREATE,
          "Set cannot be created: set with the same name already exists" },
        { IPSET_ERR_FIND_TYPE, 0,
-         "Kernel error received: set type does not supported" },
+         "Kernel error received: set type not supported" },
        { IPSET_ERR_MAX_SETS, 0,
          "Kernel error received: maximal number of sets reached, "
          "cannot create more." },
        { IPSET_ERR_INVALID_NETMASK, 0,
          "The value of the netmask parameter is invalid" },
        { IPSET_ERR_INVALID_FAMILY, 0,
-         "The protocol family not supported by the set type" },
+         "Protocol family not supported by the set type" },
 
        /* DESTROY specific error codes */
        { IPSET_ERR_BUSY, IPSET_CMD_DESTROY,
index 8ed3e101e79b7ad77fb994962796bf8d6b10106a..05f8ef34672a12db6492bc7815c63e8ad11656a8 100644 (file)
@@ -206,62 +206,54 @@ restore(char *argv0)
 static int
 call_parser(int *argc, char *argv[], const struct ipset_arg *args)
 {
-       int i = 1, ret = 0;
+       int ret = 0;
        const struct ipset_arg *arg;
        const char *optstr;
        
        /* Currently CREATE and ADT may have got additional arguments */
-       if (!args)
-               goto done;
-       for (arg = args; arg->opt; arg++) {
-               for (i = 1; i < *argc; ) {
-                       D("argc: %u, i: %u: %s vs %s",
-                         *argc, i, argv[i], arg->name[0]);
-                       if (!(ipset_match_option(argv[i], arg->name))) {
-                               i++;
+       if (!args && *argc > 1)
+               goto err_unknown;
+       while (*argc > 1) {
+               for (arg = args; arg->opt; arg++) {
+                       D("argc: %u, %s vs %s", *argc, argv[1], arg->name[0]);
+                       if (!(ipset_match_option(argv[1], arg->name)))
                                continue;
-                       }
-                       optstr = argv[i];
+
+                       optstr = argv[1];
                        /* Shift off matched option */
                        D("match %s", arg->name[0]);
-                       ipset_shift_argv(argc, argv, i);
-                       D("argc: %u, i: %u", *argc, i);
+                       ipset_shift_argv(argc, argv, 1);
                        switch (arg->has_arg) {
                        case IPSET_MANDATORY_ARG:
-                               if (i + 1 > *argc)
+                               if (*argc < 2)
                                        return exit_error(PARAMETER_PROBLEM,
                                                "Missing mandatory argument "
                                                "of option `%s'",
                                                arg->name[0]);
                                /* Fall through */
                        case IPSET_OPTIONAL_ARG:
-                               if (i + 1 <= *argc) {
-                                       ret = ipset_call_parser(session,
-                                                       arg->parse,
-                                                       optstr, arg->opt,
-                                                       argv[i]);
+                               if (*argc >= 2) {
+                                       ret = ipset_call_parser(session, arg, argv[1]);
                                        if (ret < 0)
                                                return ret;
-                                       ipset_shift_argv(argc, argv, i);
+                                       ipset_shift_argv(argc, argv, 1);
                                        break;
                                }
                                /* Fall through */
                        default:
-                               ret = ipset_call_parser(session,
-                                                       arg->parse,
-                                                       optstr, arg->opt,
-                                                       optstr);
+                               ret = ipset_call_parser(session, arg, optstr);
                                if (ret < 0)
                                        return ret;
                        }
+                       break;
                }
+               if (!arg->opt)
+                       goto err_unknown;
        }
-done:
-       if (i < *argc)
-               return exit_error(PARAMETER_PROBLEM,
-                                 "Unknown argument: `%s'",
-                                 argv[i]);
        return ret;
+
+err_unknown:
+       return exit_error(PARAMETER_PROBLEM, "Unknown argument: `%s'", argv[1]);
 }
 
 static enum ipset_adt
@@ -476,61 +468,57 @@ parse_commandline(int argc, char *argv[])
 
        /* Second: parse command */
        for (command = ipset_commands;
-            command->cmd && cmd == IPSET_CMD_NONE;
+                argc > 1 && command->cmd && cmd == IPSET_CMD_NONE;
             command++) {
-               for (i = 1; i < argc; ) {
-                       if (!ipset_match_cmd(argv[1], command->name)) {
-                               i++;
-                               continue;
-                       }
-                       if (restore_line != 0
-                           && (command->cmd == IPSET_CMD_RESTORE
-                               || command->cmd == IPSET_CMD_VERSION
-                               || command->cmd == IPSET_CMD_HELP))
+               if (!ipset_match_cmd(argv[1], command->name))
+                       continue;
+
+               if (restore_line != 0
+                   && (command->cmd == IPSET_CMD_RESTORE
+                       || command->cmd == IPSET_CMD_VERSION
+                       || command->cmd == IPSET_CMD_HELP))
+                       return exit_error(PARAMETER_PROBLEM,
+                               "Command `%s' is invalid "
+                               "in restore mode.",
+                               command->name[0]);
+               if (interactive && command->cmd == IPSET_CMD_RESTORE) {
+                       printf("Restore command ignored "
+                              "in interactive mode\n");
+                       return 0;
+               }
+
+               /* Shift off matched command arg */
+               ipset_shift_argv(&argc, argv, 1);
+               cmd = command->cmd;
+               switch (command->has_arg) {
+               case IPSET_MANDATORY_ARG:
+               case IPSET_MANDATORY_ARG2:
+                       if (argc < 2)
                                return exit_error(PARAMETER_PROBLEM,
-                                       "Command `%s' is invalid "
-                                       "in restore mode.",
+                                       "Missing mandatory argument "
+                                       "to command %s",
                                        command->name[0]);
-                               if (interactive
-                                   && command->cmd == IPSET_CMD_RESTORE) {
-                                       printf("Restore command ignored "
-                                              "in interactive mode\n");
-                               return 0;
-                       }
-
-                       /* Shift off matched command arg */
-                       ipset_shift_argv(&argc, argv, i);
-                       cmd = command->cmd;
-                       switch (command->has_arg) {
-                       case IPSET_MANDATORY_ARG:
-                       case IPSET_MANDATORY_ARG2:
-                               if (i + 1 > argc)
-                                       return exit_error(PARAMETER_PROBLEM,
-                                               "Missing mandatory argument "
-                                               "to command %s",
-                                               command->name[0]);
-                               /* Fall through */
-                       case IPSET_OPTIONAL_ARG:
-                               arg0 = argv[i];
-                               if (i + 1 <= argc)
-                                       /* Shift off first arg */
-                                       ipset_shift_argv(&argc, argv, i);
-                               break;
-                       default:
-                               break;
-                       }
-                       if (command->has_arg == IPSET_MANDATORY_ARG2) {
-                               if (i + 1 > argc)
-                                       return exit_error(PARAMETER_PROBLEM,
-                                               "Missing second mandatory "
-                                               "argument to command %s",
-                                               command->name[0]);
-                               arg1 = argv[i];
-                               /* Shift off second arg */
-                               ipset_shift_argv(&argc, argv, i);
-                       }
+                       /* Fall through */
+               case IPSET_OPTIONAL_ARG:
+                       arg0 = argv[1];
+                       if (argc >= 2)
+                               /* Shift off first arg */
+                               ipset_shift_argv(&argc, argv, 1);
+                       break;
+               default:
                        break;
                }
+               if (command->has_arg == IPSET_MANDATORY_ARG2) {
+                       if (argc < 2)
+                               return exit_error(PARAMETER_PROBLEM,
+                                       "Missing second mandatory "
+                                       "argument to command %s",
+                                       command->name[0]);
+                       arg1 = argv[1];
+                       /* Shift off second arg */
+                       ipset_shift_argv(&argc, argv, 1);
+               }
+               break;
        }
 
        /* Third: catch interactive mode, handle help, version */
@@ -565,7 +553,8 @@ parse_commandline(int argc, char *argv[])
                                argv[1]);
                return exit_error(PARAMETER_PROBLEM, "No command specified.");
        case IPSET_CMD_VERSION:
-               printf("%s v%s.\n", program_name, program_version);
+               printf("%s v%s, protocol version: %u\n",
+                      program_name, program_version, IPSET_PROTOCOL);
                if (interactive)
                        return 0;
                return exit_error(NO_PROBLEM, NULL);
index 176e1b2d77c5b4cb75e5d4b9361a100925f2c614..3601c65b2285175ad986c8b454d86da67ea4eff1 100644 (file)
@@ -23,9 +23,9 @@
 const struct ipset_commands ipset_commands[] = {
        /* Order is important */
 
-       {       /* c[reate], --create, n, -N */
+       {       /* c[reate], --create, n[ew], -N */
                .cmd = IPSET_CMD_CREATE,
-               .name = { "create", "n" },
+               .name = { "create", "new" },
                .has_arg = IPSET_MANDATORY_ARG2,
                .help = "SETNAME TYPENAME [type-specific-options]\n"
                        "        Create a new set",
@@ -143,14 +143,14 @@ ipset_match_cmd(const char *arg, const char * const name[])
 
        if (len > strlen(name[0]) || !len)
                return false;
-       else if (strncmp(arg, name[0], len) == 0)
+       else if (len > 1 &&
+                ((strncmp(arg, name[0], len) == 0) ||
+                 (name[1] != NULL && (strncmp(arg, name[1], len) == 0))))
                return true;
        else if (len != 1)
                return false;
-       else if (name[1] == NULL)
-               return tolower(arg[0]) == name[0][0];
-       else
-               return tolower(arg[0]) == name[1][0];   
+       else return tolower(arg[0]) == name[0][0] ||
+                   (name[1] != NULL && tolower(arg[0]) == name[1][0]); 
 }
 
 const struct ipset_envopts ipset_envopts[] = {
index 56e6937d932155ed90942ad8330f0fb912681486..f2a90880072738370145648c97f1c1ac360f86d4 100644 (file)
@@ -56,10 +56,10 @@ match_set(ip_set_id_t index, const struct sk_buff *skb,
 
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35)
 #define CHECK_OK       1
-#define CHECK_FAIL     0
+#define CHECK_FAIL(err)        0
 #else /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35) */
 #define        CHECK_OK        0
-#define CHECK_FAIL     (-EINVAL)
+#define CHECK_FAIL(err)        (err)
 #endif
 
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35)
@@ -110,11 +110,12 @@ set_match_v0_checkentry(const struct xt_mtchk_param *par)
        if (index == IPSET_INVALID_ID) {
                pr_warning("Cannot find set indentified by id %u to match\n",
                           info->match_set.index);
-               return CHECK_FAIL     /* error */
+               return CHECK_FAIL(-ENOENT);     /* error */
        }
        if (info->match_set.u.flags[IPSET_DIM_MAX-1] != 0) {
-               pr_warning("That's nasty!\n");
-               return CHECK_FAIL;      /* error */
+               pr_warning("Protocol error: set match dimension "
+                          "is over the limit!\n");
+               return CHECK_FAIL(-ERANGE);     /* error */
        }
 
        /* Fill out compatibility data */
@@ -167,24 +168,25 @@ set_target_v0_checkentry(const struct xt_tgchk_param *par)
        if (info->add_set.index != IPSET_INVALID_ID) {
                index = ip_set_nfnl_get_byindex(info->add_set.index);
                if (index == IPSET_INVALID_ID) {
-                       pr_warning("cannot find add_set index %u as target\n",
+                       pr_warning("Cannot find add_set index %u as target\n",
                                   info->add_set.index);
-                       return CHECK_FAIL     /* error */
+                       return CHECK_FAIL(-ENOENT);     /* error */
                }
        }
 
        if (info->del_set.index != IPSET_INVALID_ID) {
                index = ip_set_nfnl_get_byindex(info->del_set.index);
                if (index == IPSET_INVALID_ID) {
-                       pr_warning("cannot find del_set index %u as target\n",
+                       pr_warning("Cannot find del_set index %u as target\n",
                                   info->del_set.index);
-                       return CHECK_FAIL     /* error */
+                       return CHECK_FAIL(-ENOENT);     /* error */
                }
        }
        if (info->add_set.u.flags[IPSET_DIM_MAX-1] != 0 ||
            info->del_set.u.flags[IPSET_DIM_MAX-1] != 0) {
-               pr_warning("That's nasty!\n");
-               return CHECK_FAIL;      /* error */
+               pr_warning("Protocol error: SET target dimension "
+                          "is over the limit!\n");
+               return CHECK_FAIL(-ERANGE);     /* error */
        }
 
        /* Fill out compatibility data */
@@ -239,11 +241,12 @@ set_match_checkentry(const struct xt_mtchk_param *par)
        if (index == IPSET_INVALID_ID) {
                pr_warning("Cannot find set indentified by id %u to match\n",
                           info->match_set.index);
-               return CHECK_FAIL     /* error */
+               return CHECK_FAIL(-ENOENT);     /* error */
        }
        if (info->match_set.dim > IPSET_DIM_MAX) {
-               pr_warning("That's nasty!\n");
-               return CHECK_FAIL;      /* error */
+               pr_warning("Protocol error: set match dimension "
+                          "is over the limit!\n");
+               return CHECK_FAIL(-ERANGE);     /* error */
        }
 
        return CHECK_OK;
@@ -295,24 +298,25 @@ set_target_checkentry(const struct xt_tgchk_param *par)
        if (info->add_set.index != IPSET_INVALID_ID) {
                index = ip_set_nfnl_get_byindex(info->add_set.index);
                if (index == IPSET_INVALID_ID) {
-                       pr_warning("cannot find add_set index %u as target\n",
+                       pr_warning("Cannot find add_set index %u as target\n",
                                   info->add_set.index);
-                       return CHECK_FAIL     /* error */
+                       return CHECK_FAIL(-ENOENT);     /* error */
                }
        }
 
        if (info->del_set.index != IPSET_INVALID_ID) {
                index = ip_set_nfnl_get_byindex(info->del_set.index);
                if (index == IPSET_INVALID_ID) {
-                       pr_warning("cannot find del_set index %u as target\n",
+                       pr_warning("Cannot find del_set index %u as target\n",
                                   info->del_set.index);
-                       return CHECK_FAIL     /* error */
+                       return CHECK_FAIL(-ENOENT);     /* error */
                }
        }
        if (info->add_set.dim > IPSET_DIM_MAX ||
            info->del_set.flags > IPSET_DIM_MAX) {
-               pr_warning("That's nasty!\n");
-               return CHECK_FAIL;      /* error */
+               pr_warning("Protocol error: SET target dimension "
+                          "is over the limit!\n");
+               return CHECK_FAIL(-ERANGE);     /* error */
        }
 
        return CHECK_OK;
index b5450a9c1317b64204313278a41f390f64dd026f..6d6e04ff40f733f12acbbf5f2bbc5705529c5060 100644 (file)
@@ -1,6 +1,7 @@
 #ifndef _XT_SET_H
 #define _XT_SET_H
 
+#include <linux/types.h>
 #include "ip_set.h"
 
 /* Revision 0 interface: backward compatible with netfilter/iptables */
diff --git a/mconfig b/mconfig
index 03c87190fdd03dfc4a12f47ade92f3ab2cf66cc4..221fcfb0b47cb01012ee876a3db9f3d8fddfc3bf 100644 (file)
--- a/mconfig
+++ b/mconfig
@@ -1,30 +1,3 @@
 # -*- Makefile -*-
 #
-build_ACCOUNT=m
-build_CHAOS=m
-build_CHECKSUM=
-build_DELUDE=m
-build_DHCPMAC=m
-build_DNETMAP=
-build_ECHO=
-build_IPMARK=m
-build_LOGMARK=m
-build_RAWNAT=m
-build_STEAL=m
-build_SYSRQ=m
-build_TARPIT=m
-build_TEE=
-build_condition=m
-build_fuzzy=m
-build_geoip=m
-build_gradm=m
-build_iface=m
-build_ipp2p=m
-build_ipset4=m
-build_ipset6=
-build_ipv4options=m
-build_length2=m
-build_lscan=m
-build_pknock=m
-build_psd=m
-build_quota2=m
+build_ipset6=m