summaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'kernel')
-rw-r--r--kernel/Kbuild2
-rw-r--r--kernel/include/linux/netfilter/ip_set.h96
-rw-r--r--kernel/include/linux/netfilter/ip_set_bitmap.h2
-rw-r--r--kernel/include/linux/netfilter/ip_set_chash.h186
-rw-r--r--kernel/include/linux/netfilter/ip_set_getport.h62
-rw-r--r--kernel/include/linux/netfilter/ip_set_hash.h6
-rw-r--r--kernel/include/linux/netfilter/ip_set_kernel.h7
-rw-r--r--kernel/include/linux/netfilter/ip_set_list.h6
-rw-r--r--kernel/include/linux/netfilter/ip_set_slist.h9
-rw-r--r--kernel/include/linux/netfilter/ip_set_timeout.h27
-rw-r--r--kernel/ip_set.c87
-rw-r--r--kernel/ip_set_bitmap_ip.c85
-rw-r--r--kernel/ip_set_bitmap_ipmac.c49
-rw-r--r--kernel/ip_set_bitmap_port.c13
-rw-r--r--kernel/ip_set_hash_ip.c51
-rw-r--r--kernel/ip_set_hash_ipport.c97
-rw-r--r--kernel/ip_set_hash_ipportip.c121
-rw-r--r--kernel/ip_set_hash_ipportnet.c128
-rw-r--r--kernel/ip_set_hash_net.c51
-rw-r--r--kernel/ip_set_hash_netport.c566
-rw-r--r--kernel/ip_set_list_set.c6
21 files changed, 1154 insertions, 503 deletions
diff --git a/kernel/Kbuild b/kernel/Kbuild
index 9875d70..c496a93 100644
--- a/kernel/Kbuild
+++ b/kernel/Kbuild
@@ -6,7 +6,7 @@ EXTRA_CFLAGS := -I$(M)/include \
obj-m += ip_set.o xt_set.o
obj-m += ip_set_bitmap_ip.o ip_set_bitmap_ipmac.o ip_set_bitmap_port.o
obj-m += ip_set_hash_ip.o ip_set_hash_ipport.o ip_set_hash_ipportip.o
-obj-m += ip_set_hash_net.o ip_set_hash_ipportnet.o
+obj-m += ip_set_hash_net.o ip_set_hash_ipportnet.o ip_set_hash_netport.o
obj-m += ip_set_list_set.o
# It's for me...
diff --git a/kernel/include/linux/netfilter/ip_set.h b/kernel/include/linux/netfilter/ip_set.h
index 1c41396..8abf8f8 100644
--- a/kernel/include/linux/netfilter/ip_set.h
+++ b/kernel/include/linux/netfilter/ip_set.h
@@ -52,7 +52,7 @@ enum {
IPSET_ATTR_PROTOCOL, /* 1: Protocol version */
IPSET_ATTR_SETNAME, /* 2: Name of the set */
IPSET_ATTR_TYPENAME, /* 3: Typename */
- IPSET_ATTR_SETNAME2 = IPSET_ATTR_TYPENAME, /* rename/swap */
+ IPSET_ATTR_SETNAME2 = IPSET_ATTR_TYPENAME, /* Setname at rename/swap */
IPSET_ATTR_REVISION, /* 4: Settype revision */
IPSET_ATTR_FAMILY, /* 5: Settype family */
IPSET_ATTR_FLAGS, /* 6: Flags at command level */
@@ -77,7 +77,7 @@ enum {
IPSET_ATTR_TIMEOUT, /* 6 */
IPSET_ATTR_PROTO, /* 7 */
IPSET_ATTR_CADT_FLAGS, /* 8 */
- IPSET_ATTR_CADT_LINENO = IPSET_ATTR_LINENO,
+ IPSET_ATTR_CADT_LINENO = IPSET_ATTR_LINENO, /* 9 */
/* Reserve empty slots */
IPSET_ATTR_CADT_MAX = 16,
/* Create-only specific attributes */
@@ -108,6 +108,14 @@ enum {
};
#define IPSET_ATTR_ADT_MAX (__IPSET_ATTR_ADT_MAX - 1)
+/* IP specific attributes */
+enum {
+ IPSET_ATTR_IPADDR_IPV4 = IPSET_ATTR_UNSPEC + 1,
+ IPSET_ATTR_IPADDR_IPV6,
+ __IPSET_ATTR_IPADDR_MAX,
+};
+#define IPSET_ATTR_IPADDR_MAX (__IPSET_ATTR_IPADDR_MAX - 1)
+
/* Error codes */
enum ipset_errno {
IPSET_ERR_PRIVATE = 128,
@@ -123,16 +131,20 @@ enum ipset_errno {
IPSET_ERR_INVALID_FAMILY,
IPSET_ERR_TIMEOUT,
IPSET_ERR_REFERENCED,
+ IPSET_ERR_IPADDR_IPV4,
+ IPSET_ERR_IPADDR_IPV6,
/* Type specific error codes */
IPSET_ERR_TYPE_SPECIFIC = 160,
};
+/* Flags at command level */
enum ipset_cmd_flags {
IPSET_FLAG_BIT_EXIST = 0,
IPSET_FLAG_EXIST = (1 << IPSET_FLAG_BIT_EXIST),
};
+/* Flags at CADT attribute level */
enum ipset_cadt_flags {
IPSET_FLAG_BIT_BEFORE = 0,
IPSET_FLAG_BEFORE = (1 << IPSET_FLAG_BIT_BEFORE),
@@ -148,9 +160,6 @@ enum ipset_adt {
IPSET_CADT_MAX,
};
-#define IPSET_IPPROTO_ANY 255
-#define IPSET_IPPROTO_TCPUDP 254
-
#ifdef __KERNEL__
#include <linux/ip.h>
#include <linux/ipv6.h>
@@ -196,7 +205,8 @@ enum ip_set_feature {
IPSET_TYPE_IP2 = (1 << IPSET_TYPE_IP2_FLAG),
IPSET_TYPE_NAME_FLAG = 4,
IPSET_TYPE_NAME = (1 << IPSET_TYPE_NAME_FLAG),
- /* Actually just a flag for dumping */
+ /* Strictly speaking not a feature, but a flag for dumping:
+ * this settype must be dumped last */
IPSET_DUMP_LAST_FLAG = 7,
IPSET_DUMP_LAST = (1 << IPSET_DUMP_LAST_FLAG),
};
@@ -223,7 +233,7 @@ struct ip_set_type_variant {
int (*uadt)(struct ip_set *set, struct nlattr *head, int len,
enum ipset_adt adt, u32 *lineno, u32 flags);
- /* Low level add/del/test entries */
+ /* Low level add/del/test functions */
ipset_adtfn adt[IPSET_ADT_MAX];
/* When adding entries and set is full, try to resize the set */
@@ -241,7 +251,7 @@ struct ip_set_type_variant {
struct netlink_callback *cb);
/* Return true if "b" set is the same as "a"
- * according to the set parameters */
+ * according to the create set parameters */
bool (*same_set)(const struct ip_set *a, const struct ip_set *b);
};
@@ -285,7 +295,7 @@ struct ip_set {
const struct ip_set_type *type;
/* The type variant doing the real job */
const struct ip_set_type_variant *variant;
- /* The actual INET family */
+ /* The actual INET family of the set */
u8 family;
/* The type specific data */
void *data;
@@ -340,6 +350,7 @@ ip_set_free(void *members)
kfree(members);
}
+/* Ignore IPSET_ERR_EXIST errors if asked to do so? */
static inline bool
ip_set_eexist(int ret, u32 flags)
{
@@ -379,6 +390,52 @@ ip_set_get_n16(const struct nlattr *attr)
return attr->nla_type & NLA_F_NET_BYTEORDER ? value : htons(value);
}
+static const struct nla_policy
+ipaddr_policy[IPSET_ATTR_IPADDR_MAX + 1] __read_mostly = {
+ [IPSET_ATTR_IPADDR_IPV4] = { .type = NLA_U32 },
+ [IPSET_ATTR_IPADDR_IPV6] = { .type = NLA_BINARY,
+ .len = sizeof(struct in6_addr) },
+};
+
+static inline int
+ip_set_get_ipaddr4(struct nlattr *attr[], int type, u32 *ipaddr)
+{
+ struct nlattr *tb[IPSET_ATTR_IPADDR_MAX+1] = {};
+
+ if (!attr[type])
+ return -IPSET_ERR_PROTOCOL;
+
+ if (nla_parse(tb, IPSET_ATTR_IPADDR_MAX,
+ nla_data(attr[type]), nla_len(attr[type]),
+ ipaddr_policy))
+ return -IPSET_ERR_PROTOCOL;
+ if (!tb[IPSET_ATTR_IPADDR_IPV4])
+ return -IPSET_ERR_IPADDR_IPV4;
+
+ *ipaddr = ip_set_get_n32(tb[IPSET_ATTR_IPADDR_IPV4]);
+ return 0;
+}
+
+static inline int
+ip_set_get_ipaddr6(struct nlattr *attr[], int type, union nf_inet_addr *ipaddr)
+{
+ struct nlattr *tb[IPSET_ATTR_IPADDR_MAX+1] = {};
+
+ if (!attr[type])
+ return -IPSET_ERR_PROTOCOL;
+
+ if (nla_parse(tb, IPSET_ATTR_IPADDR_MAX,
+ nla_data(attr[type]), nla_len(attr[type]),
+ ipaddr_policy))
+ return -IPSET_ERR_PROTOCOL;
+ if (!tb[IPSET_ATTR_IPADDR_IPV6])
+ return -IPSET_ERR_IPADDR_IPV6;
+
+ memcpy(ipaddr, nla_data(tb[IPSET_ATTR_IPADDR_IPV6]),
+ sizeof(struct in6_addr));
+ return 0;
+}
+
#define ipset_nest_start(skb, attr) nla_nest_start(skb, attr | NLA_F_NESTED)
#define ipset_nest_end(skb, start) nla_nest_end(skb, start)
@@ -388,6 +445,27 @@ ip_set_get_n16(const struct nlattr *attr)
#define NLA_PUT_NET16(skb, type, value) \
NLA_PUT_BE16(skb, type | NLA_F_NET_BYTEORDER, value)
+#define NLA_PUT_IPADDR4(skb, type, ipaddr) \
+do { \
+ struct nlattr *__nested = ipset_nest_start(skb, type); \
+ \
+ if (!__nested) \
+ goto nla_put_failure; \
+ NLA_PUT_NET32(skb, IPSET_ATTR_IPADDR_IPV4, ipaddr); \
+ ipset_nest_end(skb, __nested); \
+} while (0)
+
+#define NLA_PUT_IPADDR6(skb, type, ipaddrptr) \
+do { \
+ struct nlattr *__nested = ipset_nest_start(skb, type); \
+ \
+ if (!__nested) \
+ goto nla_put_failure; \
+ NLA_PUT(skb, IPSET_ATTR_IPADDR_IPV6, \
+ sizeof(struct in6_addr), ipaddrptr); \
+ ipset_nest_end(skb, __nested); \
+} while (0)
+
/* Get address from skbuff */
static inline u32
ip4addr(const struct sk_buff *skb, bool src)
diff --git a/kernel/include/linux/netfilter/ip_set_bitmap.h b/kernel/include/linux/netfilter/ip_set_bitmap.h
index 0d067d0..f3bff2c 100644
--- a/kernel/include/linux/netfilter/ip_set_bitmap.h
+++ b/kernel/include/linux/netfilter/ip_set_bitmap.h
@@ -3,7 +3,9 @@
/* Bitmap type specific error codes */
enum {
+ /* The element is out of the range of the set */
IPSET_ERR_BITMAP_RANGE = IPSET_ERR_TYPE_SPECIFIC,
+ /* The range exceeds the size limit of the set type */
IPSET_ERR_BITMAP_RANGE_SIZE,
};
diff --git a/kernel/include/linux/netfilter/ip_set_chash.h b/kernel/include/linux/netfilter/ip_set_chash.h
index 5e615e4..6fd1d32 100644
--- a/kernel/include/linux/netfilter/ip_set_chash.h
+++ b/kernel/include/linux/netfilter/ip_set_chash.h
@@ -5,13 +5,11 @@
#include <linux/netfilter/ip_set_slist.h>
#include <linux/netfilter/ip_set_timeout.h>
-#define CONCAT(a, b, c) a##b##c
-#define TOKEN(a, b, c) CONCAT(a, b, c)
-
-/* Cache friendly hash with resizing when linear searching becomes too long.
- * Internally jhash is used with the assumption that the size of the stored
- * data is a multiple of sizeof(u32). If storage supports timeout, the
- * timeout field must be the last one in the data structure.
+/* Cacheline friendly hash with resizing when linear searching becomes too
+ * long. Internally jhash is used with the assumption that the size of the
+ * stored data is a multiple of sizeof(u32). If storage supports timeout,
+ * the timeout field must be the last one in the data structure - that field
+ * is ignored when computing the hash key.
*/
/* Number of elements to store in an array block */
@@ -19,9 +17,10 @@
/* Number of arrays: max ARRAY_SIZE * CHAIN_LIMIT "long" chains */
#define CHASH_DEFAULT_CHAIN_LIMIT 3
+/* Book-keeping of the prefixes added to the set */
struct chash_nets {
+ u8 cidr; /* the different cidr values in the set */
u32 nets; /* number of elements per cidr */
- u8 cidr; /* the cidr values added to the set */
};
struct chash {
@@ -37,14 +36,12 @@ struct chash {
#ifdef IP_SET_HASH_WITH_NETMASK
u8 netmask; /* netmask value for subnets to store */
#endif
-#ifdef IP_SET_HASH_WITH_PROTO
- u8 proto; /* default protocol for SET target */
-#endif
#ifdef IP_SET_HASH_WITH_NETS
- struct chash_nets nets[0]; /* book keeping of networks */
+ struct chash_nets nets[0]; /* book-keeping of prefixes */
#endif
};
+/* Compute htable_bits from the user input parameter hashsize */
static inline u8
htable_bits(u32 hashsize)
{
@@ -57,34 +54,56 @@ htable_bits(u32 hashsize)
return bits;
}
+#ifdef IP_SET_HASH_WITH_NETS
+
+#define SET_HOST_MASK(family) (family == AF_INET ? 32 : 128)
+
+/* Network cidr size book keeping when the hash stores different
+ * sized networks */
static inline void
-add_cidr(struct chash_nets *nets, u8 host_mask, u8 cidr)
+add_cidr(struct chash *h, u8 cidr, u8 host_mask)
{
u8 i;
- pr_debug("add_cidr %u", cidr);
- for (i = 0; i < host_mask - 1 && nets[i].cidr; i++) {
+ ++h->nets[cidr-1].nets;
+
+ pr_debug("add_cidr added %u: %u", cidr, h->nets[cidr-1].nets);
+
+ if (h->nets[cidr-1].nets > 1)
+ return;
+
+ /* New cidr size */
+ for (i = 0; i < host_mask && h->nets[i].cidr; i++) {
/* Add in increasing prefix order, so larger cidr first */
- if (nets[i].cidr < cidr)
- swap(nets[i].cidr, cidr);
+ if (h->nets[i].cidr < cidr)
+ swap(h->nets[i].cidr, cidr);
}
- if (i < host_mask - 1)
- nets[i].cidr = cidr;
+ if (i < host_mask)
+ h->nets[i].cidr = cidr;
}
static inline void
-del_cidr(struct chash_nets *nets, u8 host_mask, u8 cidr)
+del_cidr(struct chash *h, u8 cidr, u8 host_mask)
{
u8 i;
- pr_debug("del_cidr %u", cidr);
- for (i = 0; i < host_mask - 2 && nets[i].cidr; i++) {
- if (nets[i].cidr == cidr)
- nets[i].cidr = cidr = nets[i+1].cidr;
+ --h->nets[cidr-1].nets;
+
+ pr_debug("del_cidr deleted %u: %u", cidr, h->nets[cidr-1].nets);
+
+ if (h->nets[cidr-1].nets != 0)
+ return;
+
+ /* All entries with this cidr size deleted, so cleanup h->cidr[] */
+ for (i = 0; i < host_mask - 1 && h->nets[i].cidr; i++) {
+ if (h->nets[i].cidr == cidr)
+ h->nets[i].cidr = cidr = h->nets[i+1].cidr;
}
- nets[host_mask - 2].cidr = 0;
+ h->nets[i - 1].cidr = 0;
}
+#endif
+/* Destroy the hashtable part of the set */
static void
chash_destroy(struct slist *t, u8 htable_bits)
{
@@ -93,12 +112,13 @@ chash_destroy(struct slist *t, u8 htable_bits)
for (i = 0; i < jhash_size(htable_bits); i++)
slist_for_each_safe(n, tmp, &t[i])
- /* FIXME: slab cache */
+ /* FIXME: use slab cache */
kfree(n);
ip_set_free(t);
}
+/* Calculate the actual memory size of the set data */
static size_t
chash_memsize(const struct chash *h, size_t dsize, u8 host_mask)
{
@@ -106,7 +126,7 @@ chash_memsize(const struct chash *h, size_t dsize, u8 host_mask)
u32 i;
size_t memsize = sizeof(*h)
#ifdef IP_SET_HASH_WITH_NETS
- + sizeof(struct chash_nets) * (host_mask - 1)
+ + sizeof(struct chash_nets) * host_mask
#endif
+ jhash_size(h->htable_bits) * sizeof(struct slist);
@@ -118,6 +138,7 @@ chash_memsize(const struct chash *h, size_t dsize, u8 host_mask)
return memsize;
}
+/* Flush a hash type of set: destroy all elements */
static void
ip_set_hash_flush(struct ip_set *set)
{
@@ -133,11 +154,12 @@ ip_set_hash_flush(struct ip_set *set)
}
#ifdef IP_SET_HASH_WITH_NETS
memset(h->nets, 0, sizeof(struct chash_nets)
- * (set->family == AF_INET ? 31 : 127));
+ * SET_HOST_MASK(set->family));
#endif
h->elements = 0;
}
+/* Destroy a hash type of set */
static void
ip_set_hash_destroy(struct ip_set *set)
{
@@ -152,12 +174,15 @@ ip_set_hash_destroy(struct ip_set *set)
set->data = NULL;
}
-#define JHASH2(data, initval, htable_bits) \
-jhash2((u32 *)(data), sizeof(struct type_pf_elem)/sizeof(u32), initval) \
- & jhash_mask(htable_bits)
+#define JHASH2(data, initval, htable_bits) \
+(jhash2((u32 *)(data), sizeof(struct type_pf_elem)/sizeof(u32), initval) \
+ & jhash_mask(htable_bits))
#endif /* _IP_SET_CHASH_H */
+#define CONCAT(a, b, c) a##b##c
+#define TOKEN(a, b, c) CONCAT(a, b, c)
+
/* Type/family dependent function prototypes */
#define type_pf_data_equal TOKEN(TYPE, PF, _data_equal)
@@ -208,10 +233,13 @@ jhash2((u32 *)(data), sizeof(struct type_pf_elem)/sizeof(u32), initval) \
/* Flavour without timeout */
+/* Get the ith element from the array block n */
#define chash_data(n, i) \
(struct type_pf_elem *)((char *)(n) + sizeof(struct slist) \
+ (i)*sizeof(struct type_pf_elem))
+/* Add an element to the hash table when resizing the set:
+ * we spare the maintenance of the internal counters. */
static int
type_pf_chash_readd(struct chash *h, struct slist *t, u8 htable_bits,
const struct type_pf_elem *value, gfp_t gfp_flags)
@@ -240,7 +268,7 @@ type_pf_chash_readd(struct chash *h, struct slist *t, u8 htable_bits,
prev->next = (struct slist *) tmp;
data = chash_data(tmp, 0);
} else {
- /* Rehashing */
+ /* Trigger rehashing */
return -EAGAIN;
}
found:
@@ -248,13 +276,16 @@ found:
return 0;
}
+/* Delete an element from the hash table: swap it with the last
+ * element in the hash bucket and free up the array if it was
+ * completely emptied */
static void
type_pf_chash_del_elem(struct chash *h, struct slist *prev,
struct slist *n, int i)
{
struct type_pf_elem *data = chash_data(n, i);
struct slist *tmp;
- int j;
+ int j; /* Index in array */
if (n->next != NULL) {
for (prev = n, tmp = n->next;
@@ -276,8 +307,7 @@ type_pf_chash_del_elem(struct chash *h, struct slist *prev,
type_pf_data_swap(data, chash_data(tmp, j));
}
#ifdef IP_SET_HASH_WITH_NETS
- if (--h->nets[data->cidr-1].nets == 0)
- del_cidr(h->nets, HOST_MASK, data->cidr);
+ del_cidr(h, data->cidr, HOST_MASK);
#endif
if (j == 0) {
prev->next = NULL;
@@ -288,6 +318,9 @@ type_pf_chash_del_elem(struct chash *h, struct slist *prev,
h->elements--;
}
+/* Resize a hash: create a new hash table with doubling the hashsize
+ * and inserting the elements to it. Repeat until we succeed or
+ * fail due to memory pressures. */
static int
type_pf_resize(struct ip_set *set, gfp_t gfp_flags, bool retried)
{
@@ -299,7 +332,7 @@ type_pf_resize(struct ip_set *set, gfp_t gfp_flags, bool retried)
int ret;
retry:
- ret = 0;
+ ret = i = 0;
htable_bits++;
if (!htable_bits)
/* In case we have plenty of memory :-) */
@@ -310,8 +343,8 @@ retry:
return -ENOMEM;
write_lock_bh(&set->lock);
- for (i = 0; i < jhash_size(h->htable_bits); i++) {
next_slot:
+ for (; i < jhash_size(h->htable_bits); i++) {
slist_for_each(n, &h->htable[i]) {
for (j = 0; j < h->array_size; j++) {
data = chash_data(n, j);
@@ -344,6 +377,8 @@ next_slot:
return 0;
}
+/* Add an element to a hash and update the internal counters when succeeded,
+ * otherwise report the proper error code. */
static int
type_pf_chash_add(struct ip_set *set, void *value,
gfp_t gfp_flags, u32 timeout)
@@ -356,11 +391,7 @@ type_pf_chash_add(struct ip_set *set, void *value,
int i = 0, j = 0;
u32 hash;
-#ifdef IP_SET_HASH_WITH_NETS
- if (h->elements >= h->maxelem || h->nets[d->cidr-1].nets == UINT_MAX)
-#else
if (h->elements >= h->maxelem)
-#endif
return -IPSET_ERR_HASH_FULL;
hash = JHASH2(value, h->initval, h->htable_bits);
@@ -390,13 +421,13 @@ type_pf_chash_add(struct ip_set *set, void *value,
found:
type_pf_data_copy(data, d);
#ifdef IP_SET_HASH_WITH_NETS
- if (h->nets[d->cidr-1].nets++ == 0)
- add_cidr(h->nets, HOST_MASK, d->cidr);
+ add_cidr(h, d->cidr, HOST_MASK);
#endif
h->elements++;
return 0;
}
+/* Delete an element from the hash */
static int
type_pf_chash_del(struct ip_set *set, void *value,
gfp_t gfp_flags, u32 timeout)
@@ -423,6 +454,9 @@ type_pf_chash_del(struct ip_set *set, void *value,
}
#ifdef IP_SET_HASH_WITH_NETS
+
+/* Special test function which takes into account the different network
+ * sizes added to the set */
static inline int
type_pf_chash_test_cidrs(struct ip_set *set,
struct type_pf_elem *d,
@@ -433,11 +467,11 @@ type_pf_chash_test_cidrs(struct ip_set *set,
const struct type_pf_elem *data;
int i, j = 0;
u32 hash;
- u8 host_mask = set->family == AF_INET ? 32 : 128;
+ u8 host_mask = SET_HOST_MASK(set->family);
retry:
pr_debug("test by nets");
- for (; j < host_mask - 1 && h->nets[j].cidr; j++) {
+ for (; j < host_mask && h->nets[j].cidr; j++) {
type_pf_data_netmask(d, h->nets[j].cidr);
hash = JHASH2(d, h->initval, h->htable_bits);
slist_for_each(n, &h->htable[hash])
@@ -455,6 +489,7 @@ retry:
}
#endif
+/* Test whether the element is added to the set */
static inline int
type_pf_chash_test(struct ip_set *set, void *value,
gfp_t gfp_flags, u32 timeout)
@@ -465,10 +500,11 @@ type_pf_chash_test(struct ip_set *set, void *value,
const struct type_pf_elem *data;
int i;
u32 hash;
-#ifdef IP_SET_HASH_WITH_NETS
- u8 host_mask = set->family == AF_INET ? 32 : 128;
- if (d->cidr == host_mask)
+#ifdef IP_SET_HASH_WITH_NETS
+ /* If we test an IP address and not a network address,
+ * try all possible network sizes */
+ if (d->cidr == SET_HOST_MASK(set->family))
return type_pf_chash_test_cidrs(set, d, gfp_flags, timeout);
#endif
@@ -484,6 +520,7 @@ type_pf_chash_test(struct ip_set *set, void *value,
return 0;
}
+/* Reply a HEADER request: fill out the header part of the set */
static int
type_pf_head(struct ip_set *set, struct sk_buff *skb)
{
@@ -508,10 +545,6 @@ type_pf_head(struct ip_set *set, struct sk_buff *skb)
if (h->netmask != HOST_MASK)
NLA_PUT_U8(skb, IPSET_ATTR_NETMASK, h->netmask);
#endif
-#ifdef IP_SET_HASH_WITH_PROTO
- if (h->proto != IPSET_IPPROTO_TCPUDP)
- NLA_PUT_U8(skb, IPSET_ATTR_PROTO, h->proto);
-#endif
NLA_PUT_NET32(skb, IPSET_ATTR_REFERENCES,
htonl(atomic_read(&set->ref) - 1));
NLA_PUT_NET32(skb, IPSET_ATTR_MEMSIZE, htonl(memsize));
@@ -524,6 +557,7 @@ nla_put_failure:
return -EFAULT;
}
+/* Reply a LIST/SAVE request: dump the elements of the specified set */
static int
type_pf_list(struct ip_set *set,
struct sk_buff *skb, struct netlink_callback *cb)
@@ -599,7 +633,8 @@ static const struct ip_set_type_variant type_pf_variant __read_mostly = {
/* Flavour with timeout support */
#define chash_tdata(n, i) \
-(struct type_pf_elem *)((char *)(n) + sizeof(struct slist) + (i)*sizeof(struct type_pf_telem))
+(struct type_pf_elem *)((char *)(n) + sizeof(struct slist) \
+ + (i)*sizeof(struct type_pf_telem))
static inline u32
type_pf_data_timeout(const struct type_pf_elem *data)
@@ -666,7 +701,7 @@ type_pf_chash_treadd(struct chash *h, struct slist *t, u8 htable_bits,
prev->next = (struct slist *) tmp;
data = chash_tdata(tmp, 0);
} else {
- /* Rehashing */
+ /* Trigger rehashing */
return -EAGAIN;
}
found:
@@ -681,7 +716,7 @@ type_pf_chash_del_telem(struct chash *h, struct slist *prev,
{
struct type_pf_elem *d, *data = chash_tdata(n, i);
struct slist *tmp;
- int j;
+ int j; /* Index in array */
pr_debug("del %u", i);
if (n->next != NULL) {
@@ -706,8 +741,7 @@ type_pf_chash_del_telem(struct chash *h, struct slist *prev,
type_pf_data_swap_timeout(data, d);
}
#ifdef IP_SET_HASH_WITH_NETS
- if (--h->nets[data->cidr-1].nets == 0)
- del_cidr(h->nets, HOST_MASK, data->cidr);
+ del_cidr(h, data->cidr, HOST_MASK);
#endif
if (j == 0) {
prev->next = NULL;
@@ -718,6 +752,7 @@ type_pf_chash_del_telem(struct chash *h, struct slist *prev,
h->elements--;
}
+/* Delete expired elements from the hashtable */
static void
type_pf_chash_expire(struct chash *h)
{
@@ -760,7 +795,7 @@ type_pf_tresize(struct ip_set *set, gfp_t gfp_flags, bool retried)
}
retry:
- ret = 0;
+ ret = i = 0;
htable_bits++;
if (!htable_bits)
/* In case we have plenty of memory :-) */
@@ -771,8 +806,8 @@ retry:
return -ENOMEM;
write_lock_bh(&set->lock);
- for (i = 0; i < jhash_size(h->htable_bits); i++) {
next_slot:
+ for (; i < jhash_size(h->htable_bits); i++) {
slist_for_each(n, &h->htable[i]) {
for (j = 0; j < h->array_size; j++) {
data = chash_tdata(n, j);
@@ -781,8 +816,8 @@ next_slot:
goto next_slot;
}
ret = type_pf_chash_treadd(h, t, htable_bits,
- data, gfp_flags,
- type_pf_data_timeout(data));
+ data, gfp_flags,
+ type_pf_data_timeout(data));
if (ret < 0) {
write_unlock_bh(&set->lock);
chash_destroy(t, htable_bits);
@@ -821,11 +856,7 @@ type_pf_chash_tadd(struct ip_set *set, void *value,
if (h->elements >= h->maxelem)
/* FIXME: when set is full, we slow down here */
type_pf_chash_expire(h);
-#ifdef IP_SET_HASH_WITH_NETS
- if (h->elements >= h->maxelem || h->nets[d->cidr-1].nets == UINT_MAX)
-#else
if (h->elements >= h->maxelem)
-#endif
return -IPSET_ERR_HASH_FULL;
hash = JHASH2(d, h->initval, h->htable_bits);
@@ -854,17 +885,14 @@ type_pf_chash_tadd(struct ip_set *set, void *value,
return -EAGAIN;
}
found:
- if (type_pf_data_isnull(data)) {
+ if (type_pf_data_isnull(data))
h->elements++;
#ifdef IP_SET_HASH_WITH_NETS
- } else {
- if (--h->nets[data->cidr-1].nets == 0)
- del_cidr(h->nets, HOST_MASK, data->cidr);
- }
- if (h->nets[d->cidr-1].nets++ == 0) {
- add_cidr(h->nets, HOST_MASK, d->cidr);
+ else
+ del_cidr(h, data->cidr, HOST_MASK);
+
+ add_cidr(h, d->cidr, HOST_MASK);
#endif
- }
type_pf_data_copy(data, d);
type_pf_data_timeout_set(data, timeout);
return 0;
@@ -908,10 +936,10 @@ type_pf_chash_ttest_cidrs(struct ip_set *set,
struct slist *n;
int i, j = 0;
u32 hash;
- u8 host_mask = set->family == AF_INET ? 32 : 128;
+ u8 host_mask = SET_HOST_MASK(set->family);
retry:
- for (; j < host_mask - 1 && h->nets[j].cidr; j++) {
+ for (; j < host_mask && h->nets[j].cidr; j++) {
type_pf_data_netmask(d, h->nets[j].cidr);
hash = JHASH2(d, h->initval, h->htable_bits);
slist_for_each(n, &h->htable[hash])
@@ -938,10 +966,9 @@ type_pf_chash_ttest(struct ip_set *set, void *value,
struct slist *n;
int i;
u32 hash;
-#ifdef IP_SET_HASH_WITH_NETS
- u8 host_mask = set->family == AF_INET ? 32 : 128;
- if (d->cidr == host_mask)
+#ifdef IP_SET_HASH_WITH_NETS
+ if (d->cidr == SET_HOST_MASK(set->family))
return type_pf_chash_ttest_cidrs(set, d, gfp_flags,
timeout);
#endif
@@ -1048,7 +1075,8 @@ type_pf_gc_init(struct ip_set *set)
h->gc.function = type_pf_gc;
h->gc.expires = jiffies + IPSET_GC_PERIOD(h->timeout) * HZ;
add_timer(&h->gc);
- pr_debug("gc initialized, run in every %u", IPSET_GC_PERIOD(h->timeout));
+ pr_debug("gc initialized, run in every %u",
+ IPSET_GC_PERIOD(h->timeout));
}
#undef type_pf_data_equal
diff --git a/kernel/include/linux/netfilter/ip_set_getport.h b/kernel/include/linux/netfilter/ip_set_getport.h
index cf150d3..e4d469d 100644
--- a/kernel/include/linux/netfilter/ip_set_getport.h
+++ b/kernel/include/linux/netfilter/ip_set_getport.h
@@ -2,13 +2,14 @@
#define _IP_SET_GETPORT_H
#ifdef __KERNEL__
+#include <linux/icmp.h>
+#include <linux/icmpv6.h>
#include <linux/netfilter_ipv6/ip6_tables.h>
#include <net/ip.h>
#define IPSET_INVALID_PORT 65536
/* We must handle non-linear skbs */
-
static inline bool
get_port(const struct sk_buff *skb, int protocol, unsigned int protooff,
bool src, u16 *port, u8 *proto)
@@ -38,13 +39,32 @@ get_port(const struct sk_buff *skb, int protocol, unsigned int protooff,
*port = src ? uh->source : uh->dest;
break;
}
- default:
- if (*proto == IPSET_IPPROTO_TCPUDP)
+ case IPPROTO_ICMP: {
+ struct icmphdr _icmph;
+ const struct icmphdr *ic;
+
+ ic = skb_header_pointer(skb, protooff, sizeof(_icmph), &_icmph);
+ if (ic == NULL)
+ return false;
+
+ *port = (ic->type << 8) & ic->code;
+ break;
+ }
+ case IPPROTO_ICMPV6: {
+ struct icmp6hdr _icmph;
+ const struct icmp6hdr *ic;
+
+ ic = skb_header_pointer(skb, protooff, sizeof(_icmph), &_icmph);
+ if (ic == NULL)
return false;
+
+ *port = (ic->icmp6_type << 8) & ic->icmp6_code;
+ break;
+ }
+ default:
break;
}
- if (*proto != IPSET_IPPROTO_TCPUDP)
- *proto = protocol;
+ *proto = protocol;
return true;
}
@@ -56,9 +76,6 @@ get_ip4_port(const struct sk_buff *skb, bool src, u16 *port, u8 *proto)
unsigned int protooff = ip_hdrlen(skb);
int protocol = iph->protocol;
- if (!(*proto >= IPSET_IPPROTO_TCPUDP || *proto == protocol))
- return false;
-
/* See comments at tcp_match in ip_tables.c */
if (ntohs(iph->frag_off) & IP_OFFSET)
return false;
@@ -77,21 +94,32 @@ get_ip6_port(const struct sk_buff *skb, bool src, u16 *port, u8 *proto)
if (protocol < 0 || fragoff)
return false;
- if (!(*proto >= IPSET_IPPROTO_TCPUDP || *proto == protocol))
- return false;
-
return get_port(skb, protocol, protooff, src, port, proto);
}
static inline bool
get_ip_port(const struct sk_buff *skb, u8 pf, bool src, u16 *port)
{
- u8 proto = IPSET_IPPROTO_TCPUDP;
-
- if (pf == AF_INET)
- return get_ip4_port(skb, src, port, &proto);
- else
- return get_ip6_port(skb, src, port, &proto);
+ bool ret;
+ u8 proto;
+
+ switch (pf) {
+ case AF_INET:
+ ret = get_ip4_port(skb, src, port, &proto);
+ case AF_INET6:
+ ret = get_ip6_port(skb, src, port, &proto);
+ default:
+ return false;
+ }
+ if (!ret)
+ return ret;
+ switch (proto) {
+ case IPPROTO_TCP:
+ case IPPROTO_UDP:
+ return true;
+ default:
+ return false;
+ }
}
#endif /* __KERNEL__ */
diff --git a/kernel/include/linux/netfilter/ip_set_hash.h b/kernel/include/linux/netfilter/ip_set_hash.h
index 4003af0..e149a2b 100644
--- a/kernel/include/linux/netfilter/ip_set_hash.h
+++ b/kernel/include/linux/netfilter/ip_set_hash.h
@@ -1,11 +1,15 @@
#ifndef __IP_SET_HASH_H
#define __IP_SET_HASH_H
-/* Bitmap type specific error codes */
+/* Hash type specific error codes */
enum {
+ /* Hash is full */
IPSET_ERR_HASH_FULL = IPSET_ERR_TYPE_SPECIFIC,
+ /* Null-valued element */
IPSET_ERR_HASH_ELEM,
+ /* Invalid protocol */
IPSET_ERR_INVALID_PROTO,
+ /* Protocol missing but must be specified */
IPSET_ERR_MISSING_PROTO,
};
diff --git a/kernel/include/linux/netfilter/ip_set_kernel.h b/kernel/include/linux/netfilter/ip_set_kernel.h
index 0f04217..d770589 100644
--- a/kernel/include/linux/netfilter/ip_set_kernel.h
+++ b/kernel/include/linux/netfilter/ip_set_kernel.h
@@ -1,13 +1,6 @@
#ifndef _IP_SET_KERNEL_H
#define _IP_SET_KERNEL_H
-/* Copyright (C) 2003-2010 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
- * published by the Free Software Foundation.
- */
-
#ifdef __KERNEL__
#ifdef CONFIG_DEBUG_KERNEL
diff --git a/kernel/include/linux/netfilter/ip_set_list.h b/kernel/include/linux/netfilter/ip_set_list.h
index c40643e..9988570 100644
--- a/kernel/include/linux/netfilter/ip_set_list.h
+++ b/kernel/include/linux/netfilter/ip_set_list.h
@@ -3,11 +3,17 @@
/* List type specific error codes */
enum {
+ /* Set name to be added/deleted/tested does not exist. */
IPSET_ERR_NAME = IPSET_ERR_TYPE_SPECIFIC,
+ /* list:set type is not permitted to add */
IPSET_ERR_LOOP,
+ /* Missing reference set */
IPSET_ERR_BEFORE,
+ /* Reference set does not exist */
IPSET_ERR_NAMEREF,
+ /* Set is full */
IPSET_ERR_LIST_FULL,
+ /* Reference set is not added to the set */
IPSET_ERR_REF_EXIST,
};
diff --git a/kernel/include/linux/netfilter/ip_set_slist.h b/kernel/include/linux/netfilter/ip_set_slist.h
index abc5afe..3e8d8b0 100644
--- a/kernel/include/linux/netfilter/ip_set_slist.h
+++ b/kernel/include/linux/netfilter/ip_set_slist.h
@@ -25,7 +25,8 @@ struct slist {
pos = pos->next)
#define slist_for_each_prev(prev, pos, head) \
- for (prev = head, pos = (head)->next; pos && ({ prefetch(pos->next); 1; }); \
+ for (prev = head, pos = (head)->next; \
+ pos && ({ prefetch(pos->next); 1; }); \
prev = pos, pos = pos->next)
#define slist_for_each_safe(pos, n, head) \
@@ -46,7 +47,8 @@ struct slist {
pos = pos->next)
/**
- * slist_for_each_entry_continue - iterate over a hlist continuing after current point
+ * slist_for_each_entry_continue - iterate over a hlist continuing
+ * after current point
* @tpos: the type * to use as a loop cursor.
* @pos: the &struct slist to use as a loop cursor.
* @member: the name of the slist within the struct.
@@ -58,7 +60,8 @@ struct slist {
pos = pos->next)
/**
- * slist_for_each_entry_from - iterate over a hlist continuing from current point
+ * slist_for_each_entry_from - iterate over a hlist continuing
+ * from current point
* @tpos: the type * to use as a loop cursor.
* @pos: the &struct slist to use as a loop cursor.
* @member: the name of the slist within the struct.
diff --git a/kernel/include/linux/netfilter/ip_set_timeout.h b/kernel/include/linux/netfilter/ip_set_timeout.h
index bf1cbf6..b917480 100644
--- a/kernel/include/linux/netfilter/ip_set_timeout.h
+++ b/kernel/include/linux/netfilter/ip_set_timeout.h
@@ -17,7 +17,7 @@
#define IPSET_GC_PERIOD(timeout) \
((timeout/3) ? min_t(u32, (timeout)/3, IPSET_GC_TIME) : 1)
-/* Set is defined without timeout support */
+/* Set is defined without timeout support: timeout value may be 0 */
#define IPSET_NO_TIMEOUT UINT_MAX
#define with_timeout(timeout) ((timeout) != IPSET_NO_TIMEOUT)
@@ -27,11 +27,14 @@ ip_set_timeout_uget(struct nlattr *tb)
{
unsigned int timeout = ip_set_get_h32(tb);
+ /* Userspace supplied TIMEOUT parameter: adjust crazy size */
return timeout == IPSET_NO_TIMEOUT ? IPSET_NO_TIMEOUT - 1 : timeout;
}
#ifdef IP_SET_BITMAP_TIMEOUT
+/* Bitmap specific timeout constants and macros for the entries */
+
/* Bitmap entry is unset */
#define IPSET_ELEM_UNSET 0
/* Bitmap entry is set with no timeout value */
@@ -63,6 +66,7 @@ ip_set_timeout_set(u32 timeout)
t = timeout * HZ + jiffies;
if (t == IPSET_ELEM_UNSET || t == IPSET_ELEM_PERMANENT)
+ /* Bingo! */
t++;
return t;
@@ -76,19 +80,23 @@ ip_set_timeout_get(unsigned long timeout)
#else
+/* Hash specific timeout constants and macros for the entries */
+
/* Hash entry is set with no timeout value */
-#define IPSET_ELEM_UNSET 0
+#define IPSET_ELEM_PERMANENT 0
static inline bool
ip_set_timeout_test(unsigned long timeout)
{
- return timeout == IPSET_ELEM_UNSET || time_after(timeout, jiffies);
+ return timeout == IPSET_ELEM_PERMANENT
+ || time_after(timeout, jiffies);
}
static inline bool
ip_set_timeout_expired(unsigned long timeout)
{
- return timeout != IPSET_ELEM_UNSET && time_before(timeout, jiffies);
+ return timeout != IPSET_ELEM_PERMANENT
+ && time_before(timeout, jiffies);
}
static inline unsigned long
@@ -97,10 +105,11 @@ ip_set_timeout_set(u32 timeout)
unsigned long t;
if (!timeout)
- return IPSET_ELEM_UNSET;
+ return IPSET_ELEM_PERMANENT;
t = timeout * HZ + jiffies;
- if (t == IPSET_ELEM_UNSET)
+ if (t == IPSET_ELEM_PERMANENT)
+ /* Bingo! :-) */
t++;
return t;
@@ -109,10 +118,10 @@ ip_set_timeout_set(u32 timeout)
static inline u32
ip_set_timeout_get(unsigned long timeout)
{
- return timeout == IPSET_ELEM_UNSET ? 0 : (timeout - jiffies)/HZ;
+ return timeout == IPSET_ELEM_PERMANENT ? 0 : (timeout - jiffies)/HZ;
}
-#endif /* IP_SET_BITMAP_TIMEOUT */
+#endif /* ! IP_SET_BITMAP_TIMEOUT */
#endif /* __KERNEL__ */
-#endif /*_IP_SET_TIMEOUT_H */
+#endif /* _IP_SET_TIMEOUT_H */
diff --git a/kernel/ip_set.c b/kernel/ip_set.c
index 74b2e91..a1813e2 100644
--- a/kernel/ip_set.c
+++ b/kernel/ip_set.c
@@ -91,8 +91,9 @@ find_set_type_rcu(const char *name, u8 family, u8 revision)
return type;
}
-/* Find a given set type by name and family together
- * with the supported minimal and maximum revisions.
+/* Find a given set type by name and family.
+ * If we succeeded, the supported minimal and maximum revisions are
+ * filled out.
*/
static bool
find_set_type_minmax(const char *name, u8 family,
@@ -224,7 +225,7 @@ ip_set_test(ip_set_id_t index, const struct sk_buff *skb,
read_unlock_bh(&set->lock);
if (ret == -EAGAIN) {
- /* Type requests element to be re-added */
+ /* Type requests element to be completed */
pr_debug("element must be competed, ADD is triggered");
write_lock_bh(&set->lock);
set->variant->kadt(set, skb, IPSET_ADD, family, dim, flags);
@@ -842,9 +843,10 @@ ip_set_swap(struct sock *ctnl, struct sk_buff *skb,
/* List/save set data */
-#define DUMP_ALL 0L
-#define DUMP_ONE 1L
-#define DUMP_LAST 2L
+#define DUMP_INIT 0L
+#define DUMP_ALL 1L
+#define DUMP_ONE 2L
+#define DUMP_LAST 3L
static int
ip_set_dump_done(struct netlink_callback *cb)
@@ -868,6 +870,38 @@ dump_attrs(struct nlmsghdr *nlh)
}
}
+static inline int
+dump_init(struct netlink_callback *cb)
+{
+ struct nlmsghdr *nlh = nlmsg_hdr(cb->skb);
+ int min_len = NLMSG_SPACE(sizeof(struct nfgenmsg));
+ struct nlattr *cda[IPSET_ATTR_CMD_MAX+1];
+ struct nlattr *attr = (void *)nlh + min_len;
+ ip_set_id_t index;
+
+ /* Second pass, so parser can't fail */
+ nla_parse(cda, IPSET_ATTR_CMD_MAX,
+ attr, nlh->nlmsg_len - min_len, ip_set_setname_policy);
+
+ /* cb->args[0] : dump single set/all sets
+ * [1] : set index
+ * [..]: type specific
+ */
+
+ if (!cda[IPSET_ATTR_SETNAME]) {
+ cb->args[0] = DUMP_ALL;
+ return 0;
+ }
+
+ index = find_set_id(nla_data(cda[IPSET_ATTR_SETNAME]));
+ if (index == IPSET_INVALID_ID)
+ return -EEXIST;
+
+ cb->args[0] = DUMP_ONE;
+ cb->args[1] = index;
+ return 0;
+}
+
static int
ip_set_dump_start(struct sk_buff *skb, struct netlink_callback *cb)
{
@@ -877,6 +911,16 @@ ip_set_dump_start(struct sk_buff *skb, struct netlink_callback *cb)
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) {
+ /* We have to create and send the error message
+ * manually :-( */
+ netlink_ack(cb->skb, nlmsg_hdr(cb->skb), ret);
+ return ret;
+ }
+ }
+
if (cb->args[1] >= ip_set_max)
goto out;
@@ -971,28 +1015,12 @@ ip_set_dump(struct sock *ctnl, struct sk_buff *skb,
NFNL_CB_CONST struct nlmsghdr *nlh,
NFNL_CB_CONST struct nlattr * NFNL_CB_CONST attr[])
{
- ip_set_id_t index;
-
if (unlikely(protocol_failed(attr)))
return -IPSET_ERR_PROTOCOL;
- if (!attr[IPSET_ATTR_SETNAME])
- return netlink_dump_start(ctnl, skb, nlh,
- ip_set_dump_start,
- ip_set_dump_done);
-
- index = find_set_id(nla_data(attr[IPSET_ATTR_SETNAME]));
- if (index == IPSET_INVALID_ID)
- return -EEXIST;
-
- /* cb->args[0] : dump single set/all sets
- * [1] : set index
- * [..]: type specific
- */
- return netlink_dump_init(ctnl, skb, nlh,
- ip_set_dump_start,
- ip_set_dump_done,
- 2, DUMP_ONE, index);
+ return netlink_dump_start(ctnl, skb, nlh,
+ ip_set_dump_start,
+ ip_set_dump_done);
}
/* Add, del and test */
@@ -1025,7 +1053,8 @@ call_ad(struct sock *ctnl, struct sk_buff *skb,
write_unlock_bh(&set->lock);
} while (ret == -EAGAIN
&& set->variant->resize
- && (ret = set->variant->resize(set, GFP_KERNEL, retried++)) == 0);
+ && (ret = set->variant->resize(set, GFP_ATOMIC,
+ retried++)) == 0);
if (!ret || (ret == -IPSET_ERR_EXIST && eexist))
return 0;
@@ -1240,7 +1269,8 @@ ip_set_type(struct sock *ctnl, struct sk_buff *skb,
/* Try to load in the type module */
load_type_module(typename);
if (!find_set_type_minmax(typename, family, &min, &max)) {
- pr_debug("can't find: %s, family: %u", typename, family);
+ pr_debug("can't find: %s, family: %u",
+ typename, family);
return -EEXIST;
}
}
@@ -1503,7 +1533,8 @@ ip_set_init(void)
if (ip_set_max >= IPSET_INVALID_ID)
ip_set_max = IPSET_INVALID_ID - 1;
- ip_set_list = kzalloc(sizeof(struct ip_set *) * ip_set_max, GFP_KERNEL);
+ ip_set_list = kzalloc(sizeof(struct ip_set *) * ip_set_max,
+ GFP_KERNEL);
if (!ip_set_list) {
pr_err("ip_set: Unable to create ip_set_list");
return -ENOMEM;
diff --git a/kernel/ip_set_bitmap_ip.c b/kernel/ip_set_bitmap_ip.c
index 76baa13..5bb6a3c 100644
--- a/kernel/ip_set_bitmap_ip.c
+++ b/kernel/ip_set_bitmap_ip.c
@@ -103,8 +103,8 @@ bitmap_ip_kadt(struct ip_set *set, const struct sk_buff *skb,
static const struct nla_policy
bitmap_ip_adt_policy[IPSET_ATTR_ADT_MAX+1] __read_mostly = {
- [IPSET_ATTR_IP] = { .type = NLA_U32 },
- [IPSET_ATTR_IP_TO] = { .type = NLA_U32 },
+ [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 },
@@ -126,16 +126,16 @@ bitmap_ip_uadt(struct ip_set *set, struct nlattr *head, int len,
if (tb[IPSET_ATTR_LINENO])
*lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
- if (tb[IPSET_ATTR_IP])
- ip = ip_set_get_h32(tb[IPSET_ATTR_IP]);
- else
- return -IPSET_ERR_PROTOCOL;
+ ret = ip_set_get_ipaddr4(tb, IPSET_ATTR_IP, &ip);
+ if (ret)
+ return ret;
+ ip = ntohl(ip);
if (ip < map->first_ip || ip > map->last_ip)
return -IPSET_ERR_BITMAP_RANGE;
- /* Set was defined without timeout support,
- * don't ignore attribute silently */
+ /* Set was defined without timeout support:
+ * don't ignore the attribute silently */
if (tb[IPSET_ATTR_TIMEOUT])
return -IPSET_ERR_TIMEOUT;
@@ -143,7 +143,10 @@ bitmap_ip_uadt(struct ip_set *set, struct nlattr *head, int len,
return bitmap_ip_test(map, ip_to_id(map, ip));
if (tb[IPSET_ATTR_IP_TO]) {
- ip_to = ip_set_get_h32(tb[IPSET_ATTR_IP_TO]);
+ ret = ip_set_get_ipaddr4(tb, IPSET_ATTR_IP_TO, &ip_to);
+ if (ret)
+ return ret;
+ ip_to = ntohl(ip_to);
if (ip > ip_to) {
swap(ip, ip_to);
if (ip < map->first_ip)
@@ -203,8 +206,8 @@ bitmap_ip_head(struct ip_set *set, struct sk_buff *skb)
nested = ipset_nest_start(skb, IPSET_ATTR_DATA);
if (!nested)
goto nla_put_failure;
- NLA_PUT_NET32(skb, IPSET_ATTR_IP, htonl(map->first_ip));
- NLA_PUT_NET32(skb, IPSET_ATTR_IP_TO, htonl(map->last_ip));
+ 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,
@@ -241,8 +244,8 @@ bitmap_ip_list(struct ip_set *set,
} else
goto nla_put_failure;
}
- NLA_PUT_NET32(skb, IPSET_ATTR_IP,
- htonl(map->first_ip + id * map->hosts));
+ NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP,
+ htonl(map->first_ip + id * map->hosts));
ipset_nest_end(skb, nested);
}
ipset_nest_end(skb, atd);
@@ -280,7 +283,7 @@ static const struct ip_set_type_variant bitmap_ip __read_mostly = {
/* Timeout variant */
struct bitmap_ip_timeout {
- void *members; /* the set members */
+ 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 */
@@ -295,21 +298,17 @@ struct bitmap_ip_timeout {
static inline bool
bitmap_ip_timeout_test(const struct bitmap_ip_timeout *map, u32 id)
{
- unsigned long *table = map->members;
-
- return ip_set_timeout_test(table[id]);
+ return ip_set_timeout_test(map->members[id]);
}
static inline int
bitmap_ip_timeout_add(struct bitmap_ip_timeout *map,
u32 id, u32 timeout)
{
- unsigned long *table = map->members;
-
if (bitmap_ip_timeout_test(map, id))
return -IPSET_ERR_EXIST;
- table[id] = ip_set_timeout_set(timeout);
+ map->members[id] = ip_set_timeout_set(timeout);
return 0;
}
@@ -317,13 +316,12 @@ bitmap_ip_timeout_add(struct bitmap_ip_timeout *map,
static inline int
bitmap_ip_timeout_del(struct bitmap_ip_timeout *map, u32 id)
{
- unsigned long *table = map->members;
int ret = -IPSET_ERR_EXIST;
if (bitmap_ip_timeout_test(map, id))
ret = 0;
- table[id] = IPSET_ELEM_UNSET;
+ map->members[id] = IPSET_ELEM_UNSET;
return ret;
}
@@ -368,10 +366,10 @@ bitmap_ip_timeout_uadt(struct ip_set *set, struct nlattr *head, int len,
if (tb[IPSET_ATTR_LINENO])
*lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
- if (tb[IPSET_ATTR_IP])
- ip = ip_set_get_h32(tb[IPSET_ATTR_IP]);
- else
- return -IPSET_ERR_PROTOCOL;
+ ret = ip_set_get_ipaddr4(tb, IPSET_ATTR_IP, &ip);
+ if (ret)
+ return ret;
+ ip = ntohl(ip);
if (ip < map->first_ip || ip > map->last_ip)
return -IPSET_ERR_BITMAP_RANGE;
@@ -381,7 +379,10 @@ bitmap_ip_timeout_uadt(struct ip_set *set, struct nlattr *head, int len,
ip_to_id((const struct bitmap_ip *)map, ip));
if (tb[IPSET_ATTR_IP_TO]) {
- ip_to = ip_set_get_h32(tb[IPSET_ATTR_IP_TO]);
+ ret = ip_set_get_ipaddr4(tb, IPSET_ATTR_IP_TO, &ip_to);
+ if (ret)
+ return ret;
+ ip_to = ntohl(ip_to);
if (ip > ip_to) {
swap(ip, ip_to);
if (ip < map->first_ip)
@@ -434,7 +435,7 @@ bitmap_ip_timeout_flush(struct ip_set *set)
{
struct bitmap_ip_timeout *map = set->data;
- memset(map->members, 0, map->memsize);
+ memset(map->members, IPSET_ELEM_UNSET, map->memsize);
}
static int
@@ -446,11 +447,11 @@ bitmap_ip_timeout_head(struct ip_set *set, struct sk_buff *skb)
nested = ipset_nest_start(skb, IPSET_ATTR_DATA);
if (!nested)
goto nla_put_failure;
- NLA_PUT_NET32(skb, IPSET_ATTR_IP, htonl(map->first_ip));
- NLA_PUT_NET32(skb, IPSET_ATTR_IP_TO, htonl(map->last_ip));
+ 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_TIMEOUT , htonl(map->timeout));
+ 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,
@@ -486,8 +487,8 @@ bitmap_ip_timeout_list(struct ip_set *set,
} else
goto nla_put_failure;
}
- NLA_PUT_NET32(skb, IPSET_ATTR_IP,
- htonl(map->first_ip + id * map->hosts));
+ 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);
@@ -563,8 +564,8 @@ bitmap_ip_gc_init(struct ip_set *set)
static const struct nla_policy
bitmap_ip_create_policy[IPSET_ATTR_CREATE_MAX+1] __read_mostly = {
- [IPSET_ATTR_IP] = { .type = NLA_U32 },
- [IPSET_ATTR_IP_TO] = { .type = NLA_U32 },
+ [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 },
@@ -597,18 +598,22 @@ bitmap_ip_create(struct ip_set *set, struct nlattr *head, int len,
struct nlattr *tb[IPSET_ATTR_CREATE_MAX+1];
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 (tb[IPSET_ATTR_IP])
- first_ip = ip_set_get_h32(tb[IPSET_ATTR_IP]);
- else
- return -IPSET_ERR_PROTOCOL;
+ ret = ip_set_get_ipaddr4(tb, IPSET_ATTR_IP, &first_ip);
+ if (ret)
+ return ret;
+ first_ip = ntohl(first_ip);
if (tb[IPSET_ATTR_IP_TO]) {
- last_ip = ip_set_get_h32(tb[IPSET_ATTR_IP_TO]);
+ ret = ip_set_get_ipaddr4(tb, IPSET_ATTR_IP_TO, &last_ip);
+ if (ret)
+ return ret;
+ last_ip = htonl(last_ip);
if (first_ip > last_ip) {
u32 tmp = first_ip;
diff --git a/kernel/ip_set_bitmap_ipmac.c b/kernel/ip_set_bitmap_ipmac.c
index c595e18..6778819 100644
--- a/kernel/ip_set_bitmap_ipmac.c
+++ b/kernel/ip_set_bitmap_ipmac.c
@@ -51,6 +51,7 @@ struct bitmap_ipmac {
size_t dsize; /* size of element */
};
+/* ADT structure for generic function args */
struct ipmac {
u32 id; /* id in array */
unsigned char *ether; /* ethernet address */
@@ -133,7 +134,7 @@ bitmap_ipmac_add(struct ip_set *set, void *value,
if (!data->ether)
/* Already added without ethernet address */
return -IPSET_ERR_EXIST;
- /* Fill the MAC address and activate the timer */
+ /* Fill the MAC address */
memcpy(elem->ether, data->ether, ETH_ALEN);
elem->match = MAC_FILLED;
break;
@@ -192,8 +193,8 @@ bitmap_ipmac_list(struct ip_set *set,
} else
goto nla_put_failure;
}
- NLA_PUT_NET32(skb, IPSET_ATTR_IP,
- htonl(map->first_ip + id));
+ NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP,
+ htonl(map->first_ip + id));
if (elem->match == MAC_FILLED)
NLA_PUT(skb, IPSET_ATTR_ETHER, ETH_ALEN,
elem->ether);
@@ -255,7 +256,7 @@ bitmap_ipmac_tadd(struct ip_set *set, void *value,
elem->timeout = ip_set_timeout_set(timeout);
break;
case MAC_FILLED:
- if (bitmap_expired(map, data->id))
+ if (!bitmap_expired(map, data->id))
return -IPSET_ERR_EXIST;
/* Fall through */
case MAC_EMPTY:
@@ -264,7 +265,7 @@ bitmap_ipmac_tadd(struct ip_set *set, void *value,
elem->match = MAC_FILLED;
} else
elem->match = MAC_UNSET;
- /* If MAC is unset yet, we store plain timeout
+ /* If MAC is unset yet, we store plain timeout value
* because the timer is not activated yet
* and we can reuse it later when MAC is filled out,
* possibly by the kernel */
@@ -318,8 +319,8 @@ bitmap_ipmac_tlist(struct ip_set *set,
} else
goto nla_put_failure;
}
- NLA_PUT_NET32(skb, IPSET_ATTR_IP,
- htonl(map->first_ip + id));
+ NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP,
+ htonl(map->first_ip + id));
if (elem->match == MAC_FILLED)
NLA_PUT(skb, IPSET_ATTR_ETHER, ETH_ALEN,
elem->ether);
@@ -365,7 +366,7 @@ bitmap_ipmac_kadt(struct ip_set *set, const struct sk_buff *skb,
static const struct nla_policy
bitmap_ipmac_adt_policy[IPSET_ATTR_ADT_MAX + 1] __read_mostly = {
- [IPSET_ATTR_IP] = { .type = NLA_U32 },
+ [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 },
@@ -389,10 +390,10 @@ bitmap_ipmac_uadt(struct ip_set *set, struct nlattr *head, int len,
if (tb[IPSET_ATTR_LINENO])
*lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
- if (tb[IPSET_ATTR_IP])
- data.id = ip_set_get_h32(tb[IPSET_ATTR_IP]);
- else
- return -IPSET_ERR_PROTOCOL;
+ ret = ip_set_get_ipaddr4(tb, IPSET_ATTR_IP, &data.id);
+ if (ret)
+ return ret;
+ data.id = ntohl(data.id);
if (data.id < map->first_ip || data.id > map->last_ip)
return -IPSET_ERR_BITMAP_RANGE;
@@ -410,7 +411,7 @@ bitmap_ipmac_uadt(struct ip_set *set, struct nlattr *head, int len,
data.id -= map->first_ip;
- ret = adtfn(set, &data, GFP_KERNEL, timeout);
+ ret = adtfn(set, &data, GFP_ATOMIC, timeout);
return ip_set_eexist(ret, flags) ? 0 : ret;
}
@@ -447,8 +448,8 @@ bitmap_ipmac_head(struct ip_set *set, struct sk_buff *skb)
nested = ipset_nest_start(skb, IPSET_ATTR_DATA);
if (!nested)
goto nla_put_failure;
- NLA_PUT_NET32(skb, IPSET_ATTR_IP, htonl(map->first_ip));
- NLA_PUT_NET32(skb, IPSET_ATTR_IP_TO, htonl(map->last_ip));
+ NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, htonl(map->first_ip));
+ NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP_TO, htonl(map->last_ip));
NLA_PUT_NET32(skb, IPSET_ATTR_REFERENCES,
htonl(atomic_read(&set->ref) - 1));
NLA_PUT_NET32(skb, IPSET_ATTR_MEMSIZE,
@@ -543,8 +544,8 @@ bitmap_ipmac_gc_init(struct ip_set *set)
static const struct nla_policy
bitmap_ipmac_create_policy[IPSET_ATTR_CREATE_MAX+1] __read_mostly = {
- [IPSET_ATTR_IP] = { .type = NLA_U32 },
- [IPSET_ATTR_IP_TO] = { .type = NLA_U32 },
+ [IPSET_ATTR_IP] = { .type = NLA_NESTED },
+ [IPSET_ATTR_IP_TO] = { .type = NLA_NESTED },
[IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
};
@@ -573,18 +574,22 @@ bitmap_ipmac_create(struct ip_set *set, struct nlattr *head, int len,
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 (tb[IPSET_ATTR_IP])
- first_ip = ip_set_get_h32(tb[IPSET_ATTR_IP]);
- else
- return -IPSET_ERR_PROTOCOL;
+ ret = ip_set_get_ipaddr4(tb, IPSET_ATTR_IP, &first_ip);
+ if (ret)
+ return ret;
+ first_ip = ntohl(first_ip);
if (tb[IPSET_ATTR_IP_TO]) {
- last_ip = ip_set_get_h32(tb[IPSET_ATTR_IP_TO]);
+ ret = ip_set_get_ipaddr4(tb, IPSET_ATTR_IP_TO, &last_ip);
+ if (ret)
+ return ret;
+ last_ip = ntohl(last_ip);
if (first_ip > last_ip) {
u32 tmp = first_ip;
diff --git a/kernel/ip_set_bitmap_port.c b/kernel/ip_set_bitmap_port.c
index c385f99..27363f6 100644
--- a/kernel/ip_set_bitmap_port.c
+++ b/kernel/ip_set_bitmap_port.c
@@ -265,7 +265,7 @@ const struct ip_set_type_variant bitmap_port __read_mostly = {
/* Timeout variant */
struct bitmap_port_timeout {
- void *members; /* the set members */
+ 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 */
@@ -277,21 +277,17 @@ struct bitmap_port_timeout {
static inline bool
bitmap_port_timeout_test(const struct bitmap_port_timeout *map, u16 id)
{
- unsigned long *timeout = map->members;
-
- return ip_set_timeout_test(timeout[id]);
+ return ip_set_timeout_test(map->members[id]);
}
static int
bitmap_port_timeout_add(const struct bitmap_port_timeout *map,
u16 id, u32 timeout)
{
- unsigned long *table = map->members;
-
if (bitmap_port_timeout_test(map, id))
return -IPSET_ERR_EXIST;
- table[id] = ip_set_timeout_set(timeout);
+ map->members[id] = ip_set_timeout_set(timeout);
return 0;
}
@@ -300,13 +296,12 @@ static int
bitmap_port_timeout_del(const struct bitmap_port_timeout *map,
u16 id)
{
- unsigned long *table = map->members;
int ret = -IPSET_ERR_EXIST;
if (bitmap_port_timeout_test(map, id))
ret = 0;
- table[id] = IPSET_ELEM_UNSET;
+ map->members[id] = IPSET_ELEM_UNSET;
return ret;
}
diff --git a/kernel/ip_set_hash_ip.c b/kernel/ip_set_hash_ip.c
index 3295b26..6fad300 100644
--- a/kernel/ip_set_hash_ip.c
+++ b/kernel/ip_set_hash_ip.c
@@ -90,7 +90,7 @@ hash_ip4_data_zero_out(struct hash_ip4_elem *elem)
static inline bool
hash_ip4_data_list(struct sk_buff *skb, const struct hash_ip4_elem *data)
{
- NLA_PUT_NET32(skb, IPSET_ATTR_IP, data->ip);
+ NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, data->ip);
return 0;
nla_put_failure:
@@ -103,7 +103,7 @@ hash_ip4_data_tlist(struct sk_buff *skb, const struct hash_ip4_elem *data)
const struct hash_ip4_telem *tdata =
(const struct hash_ip4_telem *)data;
- NLA_PUT_NET32(skb, IPSET_ATTR_IP, tdata->ip);
+ NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, tdata->ip);
NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT,
htonl(ip_set_timeout_get(tdata->timeout)));
@@ -136,8 +136,8 @@ hash_ip4_kadt(struct ip_set *set, const struct sk_buff *skb,
static const struct nla_policy
hash_ip4_adt_policy[IPSET_ATTR_ADT_MAX + 1] __read_mostly = {
- [IPSET_ATTR_IP] = { .type = NLA_U32 },
- [IPSET_ATTR_IP_TO] = { .type = NLA_U32 },
+ [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 },
@@ -160,10 +160,9 @@ hash_ip4_uadt(struct ip_set *set, struct nlattr *head, int len,
if (tb[IPSET_ATTR_LINENO])
*lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
- if (tb[IPSET_ATTR_IP])
- ip = ip_set_get_n32(tb[IPSET_ATTR_IP]);
- else
- return -IPSET_ERR_PROTOCOL;
+ ret = ip_set_get_ipaddr4(tb, IPSET_ATTR_IP, &ip);
+ if (ret)
+ return ret;
ip &= NETMASK(h->netmask);
if (ip == 0)
@@ -176,11 +175,14 @@ hash_ip4_uadt(struct ip_set *set, struct nlattr *head, int len,
}
if (adt == IPSET_TEST)
- return adtfn(set, &ip, GFP_KERNEL, timeout);
+ return adtfn(set, &ip, GFP_ATOMIC, timeout);
ip = ntohl(ip);
if (tb[IPSET_ATTR_IP_TO]) {
- ip_to = ip_set_get_h32(tb[IPSET_ATTR_IP_TO]);
+ ret = ip_set_get_ipaddr4(tb, IPSET_ATTR_IP_TO, &ip_to);
+ if (ret)
+ return ret;
+ ip_to = ntohl(ip_to);
if (ip > ip_to)
swap(ip, ip_to);
} else if (tb[IPSET_ATTR_CIDR]) {
@@ -197,7 +199,7 @@ hash_ip4_uadt(struct ip_set *set, struct nlattr *head, int len,
for (; !before(ip_to, ip); ip += hosts) {
nip = htonl(ip);
- ret = adtfn(set, &nip, GFP_KERNEL, timeout);
+ ret = adtfn(set, &nip, GFP_ATOMIC, timeout);
if (ret && !ip_set_eexist(ret, flags))
return ret;
@@ -279,7 +281,7 @@ ip6_netmask(union nf_inet_addr *ip, u8 prefix)
static inline bool
hash_ip6_data_list(struct sk_buff *skb, const struct hash_ip6_elem *data)
{
- NLA_PUT(skb, IPSET_ATTR_IP, sizeof(struct in6_addr), &data->ip);
+ NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP, &data->ip);
return 0;
nla_put_failure:
@@ -292,7 +294,7 @@ hash_ip6_data_tlist(struct sk_buff *skb, const struct hash_ip6_elem *data)
const struct hash_ip6_telem *e =
(const struct hash_ip6_telem *)data;
- NLA_PUT(skb, IPSET_ATTR_IP, sizeof(struct in6_addr), &e->ip);
+ NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP, &e->ip);
NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT,
htonl(ip_set_timeout_get(e->timeout)));
return 0;
@@ -326,8 +328,7 @@ hash_ip6_kadt(struct ip_set *set, const struct sk_buff *skb,
static const struct nla_policy
hash_ip6_adt_policy[IPSET_ATTR_ADT_MAX + 1] __read_mostly = {
- [IPSET_ATTR_IP] = { .type = NLA_BINARY,
- .len = sizeof(struct in6_addr) },
+ [IPSET_ATTR_IP] = { .type = NLA_NESTED },
[IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
[IPSET_ATTR_LINENO] = { .type = NLA_U32 },
};
@@ -339,7 +340,7 @@ hash_ip6_uadt(struct ip_set *set, struct nlattr *head, int len,
struct chash *h = set->data;
struct nlattr *tb[IPSET_ATTR_ADT_MAX+1];
ipset_adtfn adtfn = set->variant->adt[adt];
- union nf_inet_addr *ip;
+ union nf_inet_addr ip;
u32 timeout = h->timeout;
int ret;
@@ -350,13 +351,12 @@ hash_ip6_uadt(struct ip_set *set, struct nlattr *head, int len,
if (tb[IPSET_ATTR_LINENO])
*lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
- if (tb[IPSET_ATTR_IP])
- ip = nla_data(tb[IPSET_ATTR_IP]);
- else
- return -IPSET_ERR_PROTOCOL;
+ ret = ip_set_get_ipaddr6(tb, IPSET_ATTR_IP, &ip);
+ if (ret)
+ return ret;
- ip6_netmask(ip, h->netmask);
- if (ipv6_addr_any(&ip->in6))
+ ip6_netmask(&ip, h->netmask);
+ if (ipv6_addr_any(&ip.in6))
return -IPSET_ERR_HASH_ELEM;
if (tb[IPSET_ATTR_TIMEOUT]) {
@@ -365,7 +365,7 @@ hash_ip6_uadt(struct ip_set *set, struct nlattr *head, int len,
timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
}
- ret = adtfn(set, ip, GFP_KERNEL, timeout);
+ ret = adtfn(set, &ip, GFP_ATOMIC, timeout);
return ip_set_eexist(ret, flags) ? 0 : ret;
}
@@ -430,8 +430,9 @@ hash_ip_create(struct ip_set *set, struct nlattr *head, int len, u32 flags)
get_random_bytes(&h->initval, sizeof(h->initval));
h->timeout = IPSET_NO_TIMEOUT;
- h->htable = ip_set_alloc(jhash_size(h->htable_bits) * sizeof(struct slist),
- GFP_KERNEL);
+ h->htable = ip_set_alloc(
+ jhash_size(h->htable_bits) * sizeof(struct slist),
+ GFP_KERNEL);
if (!h->htable) {
kfree(h);
return -ENOMEM;
diff --git a/kernel/ip_set_hash_ipport.c b/kernel/ip_set_hash_ipport.c
index 8554c80..1dd8187 100644
--- a/kernel/ip_set_hash_ipport.c
+++ b/kernel/ip_set_hash_ipport.c
@@ -104,10 +104,9 @@ static inline bool
hash_ipport4_data_list(struct sk_buff *skb,
const struct hash_ipport4_elem *data)
{
- NLA_PUT_NET32(skb, IPSET_ATTR_IP, data->ip);
+ NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, data->ip);
NLA_PUT_NET16(skb, IPSET_ATTR_PORT, data->port);
- if (data->proto != IPSET_IPPROTO_TCPUDP)
- NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto);
+ NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto);
return 0;
nla_put_failure:
@@ -121,10 +120,9 @@ hash_ipport4_data_tlist(struct sk_buff *skb,
const struct hash_ipport4_telem *tdata =
(const struct hash_ipport4_telem *)data;
- NLA_PUT_NET32(skb, IPSET_ATTR_IP, tdata->ip);
+ NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, tdata->ip);
NLA_PUT_NET16(skb, IPSET_ATTR_PORT, tdata->port);
- if (data->proto != IPSET_IPPROTO_TCPUDP)
- NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto);
+ NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto);
NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT,
htonl(ip_set_timeout_get(tdata->timeout)));
@@ -134,8 +132,6 @@ nla_put_failure:
return 1;
}
-#define IP_SET_HASH_WITH_PROTO
-
#define PF 4
#define HOST_MASK 32
#include <linux/netfilter/ip_set_chash.h>
@@ -146,9 +142,9 @@ hash_ipport4_kadt(struct ip_set *set, const struct sk_buff *skb,
{
struct chash *h = set->data;
ipset_adtfn adtfn = set->variant->adt[adt];
- struct hash_ipport4_elem data = { .proto = h->proto };
+ struct hash_ipport4_elem data = { };
- if (!get_ip4_port(skb, flags & IPSET_DIM_ONE_SRC,
+ if (!get_ip4_port(skb, flags & IPSET_DIM_TWO_SRC,
&data.port, &data.proto))
return -EINVAL;
@@ -158,8 +154,8 @@ hash_ipport4_kadt(struct ip_set *set, const struct sk_buff *skb,
}
static const struct nla_policy
-hash_ipport4_adt_policy[IPSET_ATTR_ADT_MAX + 1] __read_mostly = {
- [IPSET_ATTR_IP] = { .type = NLA_U32 },
+hash_ipport_adt_policy[IPSET_ATTR_ADT_MAX + 1] __read_mostly = {
+ [IPSET_ATTR_IP] = { .type = NLA_NESTED },
[IPSET_ATTR_PORT] = { .type = NLA_U16 },
[IPSET_ATTR_PROTO] = { .type = NLA_U8 },
[IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
@@ -173,21 +169,20 @@ hash_ipport4_uadt(struct ip_set *set, struct nlattr *head, int len,
struct chash *h = set->data;
struct nlattr *tb[IPSET_ATTR_ADT_MAX+1];
ipset_adtfn adtfn = set->variant->adt[adt];
- struct hash_ipport4_elem data = { .proto = h->proto };
+ struct hash_ipport4_elem data = { };
u32 timeout = h->timeout;
int ret;
if (nla_parse(tb, IPSET_ATTR_ADT_MAX, head, len,
- hash_ipport4_adt_policy))
+ hash_ipport_adt_policy))
return -IPSET_ERR_PROTOCOL;
if (tb[IPSET_ATTR_LINENO])
*lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
- if (tb[IPSET_ATTR_IP])
- data.ip = ip_set_get_n32(tb[IPSET_ATTR_IP]);
- else
- return -IPSET_ERR_PROTOCOL;
+ ret = ip_set_get_ipaddr4(tb, IPSET_ATTR_IP, &data.ip);
+ if (ret)
+ return ret;
if (tb[IPSET_ATTR_PORT])
data.port = ip_set_get_n16(tb[IPSET_ATTR_PORT]);
@@ -197,15 +192,15 @@ hash_ipport4_uadt(struct ip_set *set, struct nlattr *head, int len,
if (tb[IPSET_ATTR_PROTO]) {
data.proto = nla_get_u8(tb[IPSET_ATTR_PROTO]);
- if (data.proto == 0 || data.proto >= IPSET_IPPROTO_TCPUDP)
+ if (data.proto == 0)
return -IPSET_ERR_INVALID_PROTO;
- } else if (data.proto == IPSET_IPPROTO_ANY)
+ } else
return -IPSET_ERR_MISSING_PROTO;
switch (data.proto) {
case IPPROTO_UDP:
case IPPROTO_TCP:
- case IPSET_IPPROTO_TCPUDP:
+ case IPPROTO_ICMP:
break;
default:
data.port = 0;
@@ -218,7 +213,7 @@ hash_ipport4_uadt(struct ip_set *set, struct nlattr *head, int len,
timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
}
- ret = adtfn(set, &data, GFP_KERNEL, timeout);
+ ret = adtfn(set, &data, GFP_ATOMIC, timeout);
return ip_set_eexist(ret, flags) ? 0 : ret;
}
@@ -232,7 +227,6 @@ hash_ipport_same_set(const struct ip_set *a, const struct ip_set *b)
/* Resizing changes htable_bits, so we ignore it */
return x->maxelem == y->maxelem
&& x->timeout == y->timeout
- && x->proto == y->proto
&& x->array_size == y->array_size
&& x->chain_limit == y->chain_limit;
}
@@ -297,10 +291,9 @@ static inline bool
hash_ipport6_data_list(struct sk_buff *skb,
const struct hash_ipport6_elem *data)
{
- NLA_PUT(skb, IPSET_ATTR_IP, sizeof(struct in6_addr), &data->ip);
+ NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP, &data->ip);
NLA_PUT_NET16(skb, IPSET_ATTR_PORT, data->port);
- if (data->proto != IPSET_IPPROTO_TCPUDP)
- NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto);
+ NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto);
return 0;
nla_put_failure:
@@ -314,10 +307,9 @@ hash_ipport6_data_tlist(struct sk_buff *skb,
const struct hash_ipport6_telem *e =
(const struct hash_ipport6_telem *)data;
- NLA_PUT(skb, IPSET_ATTR_IP, sizeof(struct in6_addr), &e->ip);
+ NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP, &e->ip);
NLA_PUT_NET16(skb, IPSET_ATTR_PORT, data->port);
- if (data->proto != IPSET_IPPROTO_TCPUDP)
- NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto);
+ NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto);
NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT,
htonl(ip_set_timeout_get(e->timeout)));
return 0;
@@ -339,9 +331,9 @@ hash_ipport6_kadt(struct ip_set *set, const struct sk_buff *skb,
{
struct chash *h = set->data;
ipset_adtfn adtfn = set->variant->adt[adt];
- struct hash_ipport6_elem data = { .proto = h->proto };
+ struct hash_ipport6_elem data = { };
- if (!get_ip6_port(skb, flags & IPSET_DIM_ONE_SRC,
+ if (!get_ip6_port(skb, flags & IPSET_DIM_TWO_SRC,
&data.port, &data.proto))
return -EINVAL;
@@ -350,16 +342,6 @@ hash_ipport6_kadt(struct ip_set *set, const struct sk_buff *skb,
return adtfn(set, &data, GFP_ATOMIC, h->timeout);
}
-static const struct nla_policy
-hash_ipport6_adt_policy[IPSET_ATTR_ADT_MAX + 1] __read_mostly = {
- [IPSET_ATTR_IP] = { .type = NLA_BINARY,
- .len = sizeof(struct in6_addr) },
- [IPSET_ATTR_PORT] = { .type = NLA_U16 },
- [IPSET_ATTR_PROTO] = { .type = NLA_U8 },
- [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
- [IPSET_ATTR_LINENO] = { .type = NLA_U32 },
-};
-
static int
hash_ipport6_uadt(struct ip_set *set, struct nlattr *head, int len,
enum ipset_adt adt, u32 *lineno, u32 flags)
@@ -367,22 +349,20 @@ hash_ipport6_uadt(struct ip_set *set, struct nlattr *head, int len,
struct chash *h = set->data;
struct nlattr *tb[IPSET_ATTR_ADT_MAX+1];
ipset_adtfn adtfn = set->variant->adt[adt];
- struct hash_ipport6_elem data = { .proto = h->proto };
+ struct hash_ipport6_elem data = { };
u32 timeout = h->timeout;
int ret;
if (nla_parse(tb, IPSET_ATTR_ADT_MAX, head, len,
- hash_ipport6_adt_policy))
+ hash_ipport_adt_policy))
return -IPSET_ERR_PROTOCOL;
if (tb[IPSET_ATTR_LINENO])
*lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
- if (tb[IPSET_ATTR_IP])
- memcpy(&data.ip, nla_data(tb[IPSET_ATTR_IP]),
- sizeof(struct in6_addr));
- else
- return -IPSET_ERR_PROTOCOL;
+ ret = ip_set_get_ipaddr6(tb, IPSET_ATTR_IP, &data.ip);
+ if (ret)
+ return ret;
if (tb[IPSET_ATTR_PORT])
data.port = ip_set_get_n16(tb[IPSET_ATTR_PORT]);
@@ -392,15 +372,15 @@ hash_ipport6_uadt(struct ip_set *set, struct nlattr *head, int len,
if (tb[IPSET_ATTR_PROTO]) {
data.proto = nla_get_u8(tb[IPSET_ATTR_PROTO]);
- if (data.proto == 0 || data.proto >= IPSET_IPPROTO_TCPUDP)
+ if (data.proto == 0)
return -IPSET_ERR_INVALID_PROTO;
- } else if (data.proto == IPSET_IPPROTO_ANY)
+ } else
return -IPSET_ERR_MISSING_PROTO;
switch (data.proto) {
case IPPROTO_UDP:
case IPPROTO_TCP:
- case IPSET_IPPROTO_TCPUDP:
+ case IPPROTO_ICMPV6:
break;
default:
data.port = 0;
@@ -413,7 +393,7 @@ hash_ipport6_uadt(struct ip_set *set, struct nlattr *head, int len,
timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
}
- ret = adtfn(set, &data, GFP_KERNEL, timeout);
+ ret = adtfn(set, &data, GFP_ATOMIC, timeout);
return ip_set_eexist(ret, flags) ? 0 : ret;
}
@@ -436,7 +416,6 @@ hash_ipport_create(struct ip_set *set, struct nlattr *head, int len, u32 flags)
struct nlattr *tb[IPSET_ATTR_CREATE_MAX+1];
struct chash *h;
u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM;
- u8 proto = IPSET_IPPROTO_TCPUDP; /* Backward compatibility */
if (!(set->family == AF_INET || set->family == AF_INET6))
return -IPSET_ERR_INVALID_FAMILY;
@@ -454,12 +433,6 @@ hash_ipport_create(struct ip_set *set, struct nlattr *head, int len, u32 flags)
if (tb[IPSET_ATTR_MAXELEM])
maxelem = ip_set_get_h32(tb[IPSET_ATTR_MAXELEM]);
- if (tb[IPSET_ATTR_PROTO]) {
- proto = nla_get_u8(tb[IPSET_ATTR_PROTO]);
- if (!proto)
- return -IPSET_ERR_INVALID_PROTO;
- }
-
h = kzalloc(sizeof(*h), GFP_KERNEL);
if (!h)
return -ENOMEM;
@@ -469,11 +442,11 @@ hash_ipport_create(struct ip_set *set, struct nlattr *head, int len, u32 flags)
h->array_size = CHASH_DEFAULT_ARRAY_SIZE;
h->chain_limit = CHASH_DEFAULT_CHAIN_LIMIT;
get_random_bytes(&h->initval, sizeof(h->initval));
- h->proto = proto;
h->timeout = IPSET_NO_TIMEOUT;
- h->htable = ip_set_alloc(jhash_size(h->htable_bits) * sizeof(struct slist),
- GFP_KERNEL);
+ h->htable = ip_set_alloc(
+ jhash_size(h->htable_bits) * sizeof(struct slist),
+ GFP_KERNEL);
if (!h->htable) {
kfree(h);
return -ENOMEM;
diff --git a/kernel/ip_set_hash_ipportip.c b/kernel/ip_set_hash_ipportip.c
index d2db3a9..a20f1ef 100644
--- a/kernel/ip_set_hash_ipportip.c
+++ b/kernel/ip_set_hash_ipportip.c
@@ -107,11 +107,10 @@ static inline bool
hash_ipportip4_data_list(struct sk_buff *skb,
const struct hash_ipportip4_elem *data)
{
- NLA_PUT_NET32(skb, IPSET_ATTR_IP, data->ip);
- NLA_PUT_NET32(skb, IPSET_ATTR_IP2, data->ip2);
+ NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, data->ip);
+ NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP2, data->ip2);
NLA_PUT_NET16(skb, IPSET_ATTR_PORT, data->port);
- if (data->proto != IPSET_IPPROTO_TCPUDP)
- NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto);
+ NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto);
return 0;
nla_put_failure:
@@ -125,11 +124,10 @@ hash_ipportip4_data_tlist(struct sk_buff *skb,
const struct hash_ipportip4_telem *tdata =
(const struct hash_ipportip4_telem *)data;
- NLA_PUT_NET32(skb, IPSET_ATTR_IP, tdata->ip);
- NLA_PUT_NET32(skb, IPSET_ATTR_IP2, tdata->ip2);
+ NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, tdata->ip);
+ NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP2, tdata->ip2);
NLA_PUT_NET16(skb, IPSET_ATTR_PORT, tdata->port);
- if (data->proto != IPSET_IPPROTO_TCPUDP)
- NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto);
+ NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto);
NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT,
htonl(ip_set_timeout_get(tdata->timeout)));
@@ -139,8 +137,6 @@ nla_put_failure:
return 1;
}
-#define IP_SET_HASH_WITH_PROTO
-
#define PF 4
#define HOST_MASK 32
#include <linux/netfilter/ip_set_chash.h>
@@ -151,7 +147,7 @@ hash_ipportip4_kadt(struct ip_set *set, const struct sk_buff *skb,
{
struct chash *h = set->data;
ipset_adtfn adtfn = set->variant->adt[adt];
- struct hash_ipportip4_elem data = { .proto = h->proto };
+ struct hash_ipportip4_elem data = { };
if (!get_ip4_port(skb, flags & IPSET_DIM_TWO_SRC,
&data.port, &data.proto))
@@ -164,9 +160,9 @@ hash_ipportip4_kadt(struct ip_set *set, const struct sk_buff *skb,
}
static const struct nla_policy
-hash_ipportip4_adt_policy[IPSET_ATTR_ADT_MAX + 1] __read_mostly = {
- [IPSET_ATTR_IP] = { .type = NLA_U32 },
- [IPSET_ATTR_IP2] = { .type = NLA_U32 },
+hash_ipportip_adt_policy[IPSET_ATTR_ADT_MAX + 1] __read_mostly = {
+ [IPSET_ATTR_IP] = { .type = NLA_NESTED },
+ [IPSET_ATTR_IP2] = { .type = NLA_NESTED },
[IPSET_ATTR_PORT] = { .type = NLA_U16 },
[IPSET_ATTR_PROTO] = { .type = NLA_U8 },
[IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
@@ -180,26 +176,24 @@ hash_ipportip4_uadt(struct ip_set *set, struct nlattr *head, int len,
struct chash *h = set->data;
struct nlattr *tb[IPSET_ATTR_ADT_MAX+1];
ipset_adtfn adtfn = set->variant->adt[adt];
- struct hash_ipportip4_elem data = { .proto = h->proto };
+ struct hash_ipportip4_elem data = { };
u32 timeout = h->timeout;
int ret;
if (nla_parse(tb, IPSET_ATTR_ADT_MAX, head, len,
- hash_ipportip4_adt_policy))
+ hash_ipportip_adt_policy))
return -IPSET_ERR_PROTOCOL;
if (tb[IPSET_ATTR_LINENO])
*lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
- if (tb[IPSET_ATTR_IP])
- data.ip = ip_set_get_n32(tb[IPSET_ATTR_IP]);
- else
- return -IPSET_ERR_PROTOCOL;
+ ret = ip_set_get_ipaddr4(tb, IPSET_ATTR_IP, &data.ip);
+ if (ret)
+ return ret;
- if (tb[IPSET_ATTR_IP2])
- data.ip2 = ip_set_get_n32(tb[IPSET_ATTR_IP2]);
- else
- return -IPSET_ERR_PROTOCOL;
+ ret = ip_set_get_ipaddr4(tb, IPSET_ATTR_IP2, &data.ip2);
+ if (ret)
+ return ret;
if (tb[IPSET_ATTR_PORT])
data.port = ip_set_get_n16(tb[IPSET_ATTR_PORT]);
@@ -209,15 +203,15 @@ hash_ipportip4_uadt(struct ip_set *set, struct nlattr *head, int len,
if (tb[IPSET_ATTR_PROTO]) {
data.proto = nla_get_u8(tb[IPSET_ATTR_PROTO]);
- if (data.proto == 0 || data.proto >= IPSET_IPPROTO_TCPUDP)
+ if (data.proto == 0)
return -IPSET_ERR_INVALID_PROTO;
- } else if (data.proto == IPSET_IPPROTO_ANY)
+ } else
return -IPSET_ERR_MISSING_PROTO;
switch (data.proto) {
case IPPROTO_UDP:
case IPPROTO_TCP:
- case IPSET_IPPROTO_TCPUDP:
+ case IPPROTO_ICMP:
break;
default:
data.port = 0;
@@ -230,7 +224,7 @@ hash_ipportip4_uadt(struct ip_set *set, struct nlattr *head, int len,
timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
}
- ret = adtfn(set, &data, GFP_KERNEL, timeout);
+ ret = adtfn(set, &data, GFP_ATOMIC, timeout);
return ip_set_eexist(ret, flags) ? 0 : ret;
}
@@ -244,7 +238,6 @@ hash_ipportip_same_set(const struct ip_set *a, const struct ip_set *b)
/* Resizing changes htable_bits, so we ignore it */
return x->maxelem == y->maxelem
&& x->timeout == y->timeout
- && x->proto == y->proto
&& x->array_size == y->array_size
&& x->chain_limit == y->chain_limit;
}
@@ -312,11 +305,10 @@ static inline bool
hash_ipportip6_data_list(struct sk_buff *skb,
const struct hash_ipportip6_elem *data)
{
- NLA_PUT(skb, IPSET_ATTR_IP, sizeof(struct in6_addr), &data->ip);
- NLA_PUT(skb, IPSET_ATTR_IP2, sizeof(struct in6_addr), &data->ip2);
+ NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP, &data->ip);
+ NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP2, &data->ip2);
NLA_PUT_NET16(skb, IPSET_ATTR_PORT, data->port);
- if (data->proto != IPSET_IPPROTO_TCPUDP)
- NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto);
+ NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto);
return 0;
nla_put_failure:
@@ -330,11 +322,10 @@ hash_ipportip6_data_tlist(struct sk_buff *skb,
const struct hash_ipportip6_telem *e =
(const struct hash_ipportip6_telem *)data;
- NLA_PUT(skb, IPSET_ATTR_IP, sizeof(struct in6_addr), &e->ip);
- NLA_PUT(skb, IPSET_ATTR_IP2, sizeof(struct in6_addr), &data->ip2);
+ NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP, &e->ip);
+ NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP2, &data->ip2);
NLA_PUT_NET16(skb, IPSET_ATTR_PORT, data->port);
- if (data->proto != IPSET_IPPROTO_TCPUDP)
- NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto);
+ NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto);
NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT,
htonl(ip_set_timeout_get(e->timeout)));
return 0;
@@ -356,7 +347,7 @@ hash_ipportip6_kadt(struct ip_set *set, const struct sk_buff *skb,
{
struct chash *h = set->data;
ipset_adtfn adtfn = set->variant->adt[adt];
- struct hash_ipportip6_elem data = { .proto = h->proto };
+ struct hash_ipportip6_elem data = { };
if (!get_ip6_port(skb, flags & IPSET_DIM_TWO_SRC,
&data.port, &data.proto))
@@ -368,18 +359,6 @@ hash_ipportip6_kadt(struct ip_set *set, const struct sk_buff *skb,
return adtfn(set, &data, GFP_ATOMIC, h->timeout);
}
-static const struct nla_policy
-hash_ipportip6_adt_policy[IPSET_ATTR_ADT_MAX + 1] __read_mostly = {
- [IPSET_ATTR_IP] = { .type = NLA_BINARY,
- .len = sizeof(struct in6_addr) },
- [IPSET_ATTR_IP2] = { .type = NLA_BINARY,
- .len = sizeof(struct in6_addr) },
- [IPSET_ATTR_PORT] = { .type = NLA_U16 },
- [IPSET_ATTR_PROTO] = { .type = NLA_U8 },
- [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
- [IPSET_ATTR_LINENO] = { .type = NLA_U32 },
-};
-
static int
hash_ipportip6_uadt(struct ip_set *set, struct nlattr *head, int len,
enum ipset_adt adt, u32 *lineno, u32 flags)
@@ -387,28 +366,24 @@ hash_ipportip6_uadt(struct ip_set *set, struct nlattr *head, int len,
struct chash *h = set->data;
struct nlattr *tb[IPSET_ATTR_ADT_MAX+1];
ipset_adtfn adtfn = set->variant->adt[adt];
- struct hash_ipportip6_elem data = { .proto = h->proto };
+ struct hash_ipportip6_elem data = { };
u32 timeout = h->timeout;
int ret;
if (nla_parse(tb, IPSET_ATTR_ADT_MAX, head, len,
- hash_ipportip6_adt_policy))
+ hash_ipportip_adt_policy))
return -IPSET_ERR_PROTOCOL;
if (tb[IPSET_ATTR_LINENO])
*lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
- if (tb[IPSET_ATTR_IP])
- memcpy(&data.ip, nla_data(tb[IPSET_ATTR_IP]),
- sizeof(struct in6_addr));
- else
- return -IPSET_ERR_PROTOCOL;
+ ret = ip_set_get_ipaddr6(tb, IPSET_ATTR_IP, &data.ip);
+ if (ret)
+ return ret;
- if (tb[IPSET_ATTR_IP2])
- memcpy(&data.ip2, nla_data(tb[IPSET_ATTR_IP2]),
- sizeof(struct in6_addr));
- else
- return -IPSET_ERR_PROTOCOL;
+ ret = ip_set_get_ipaddr6(tb, IPSET_ATTR_IP2, &data.ip2);
+ if (ret)
+ return ret;
if (tb[IPSET_ATTR_PORT])
data.port = ip_set_get_n16(tb[IPSET_ATTR_PORT]);
@@ -418,15 +393,15 @@ hash_ipportip6_uadt(struct ip_set *set, struct nlattr *head, int len,
if (tb[IPSET_ATTR_PROTO]) {
data.proto = nla_get_u8(tb[IPSET_ATTR_PROTO]);
- if (data.proto == 0 || data.proto >= IPSET_IPPROTO_TCPUDP)
+ if (data.proto == 0)
return -IPSET_ERR_INVALID_PROTO;
- } else if (data.proto == IPSET_IPPROTO_ANY)
+ } else
return -IPSET_ERR_MISSING_PROTO;
switch (data.proto) {
case IPPROTO_UDP:
case IPPROTO_TCP:
- case IPSET_IPPROTO_TCPUDP:
+ case IPPROTO_ICMPV6:
break;
default:
data.port = 0;
@@ -439,7 +414,7 @@ hash_ipportip6_uadt(struct ip_set *set, struct nlattr *head, int len,
timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
}
- ret = adtfn(set, &data, GFP_KERNEL, timeout);
+ ret = adtfn(set, &data, GFP_ATOMIC, timeout);
return ip_set_eexist(ret, flags) ? 0 : ret;
}
@@ -452,7 +427,6 @@ hash_ipportip_create_policy[IPSET_ATTR_CREATE_MAX+1] __read_mostly = {
[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 },
};
@@ -463,7 +437,6 @@ hash_ipportip_create(struct ip_set *set, struct nlattr *head,
struct nlattr *tb[IPSET_ATTR_CREATE_MAX+1];
struct chash *h;
u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM;
- u8 proto = IPSET_IPPROTO_TCPUDP; /* Backward compatibility */
if (!(set->family == AF_INET || set->family == AF_INET6))
return -IPSET_ERR_INVALID_FAMILY;
@@ -481,12 +454,6 @@ hash_ipportip_create(struct ip_set *set, struct nlattr *head,
if (tb[IPSET_ATTR_MAXELEM])
maxelem = ip_set_get_h32(tb[IPSET_ATTR_MAXELEM]);
- if (tb[IPSET_ATTR_PROTO]) {
- proto = nla_get_u8(tb[IPSET_ATTR_PROTO]);
- if (!proto)
- return -IPSET_ERR_INVALID_PROTO;
- }
-
h = kzalloc(sizeof(*h), GFP_KERNEL);
if (!h)
return -ENOMEM;
@@ -496,11 +463,11 @@ hash_ipportip_create(struct ip_set *set, struct nlattr *head,
h->array_size = CHASH_DEFAULT_ARRAY_SIZE;
h->chain_limit = CHASH_DEFAULT_CHAIN_LIMIT;
get_random_bytes(&h->initval, sizeof(h->initval));
- h->proto = proto;
h->timeout = IPSET_NO_TIMEOUT;
- h->htable = ip_set_alloc(jhash_size(h->htable_bits) * sizeof(struct slist),
- GFP_KERNEL);
+ h->htable = ip_set_alloc(
+ jhash_size(h->htable_bits) * sizeof(struct slist),
+ GFP_KERNEL);
if (!h->htable) {
kfree(h);
return -ENOMEM;
diff --git a/kernel/ip_set_hash_ipportnet.c b/kernel/ip_set_hash_ipportnet.c
index f2c0d07..3904168 100644
--- a/kernel/ip_set_hash_ipportnet.c
+++ b/kernel/ip_set_hash_ipportnet.c
@@ -115,12 +115,11 @@ static inline bool
hash_ipportnet4_data_list(struct sk_buff *skb,
const struct hash_ipportnet4_elem *data)
{
- NLA_PUT_NET32(skb, IPSET_ATTR_IP, data->ip);
- NLA_PUT_NET32(skb, IPSET_ATTR_IP2, data->ip2);
+ NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, data->ip);
+ NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP2, data->ip2);
NLA_PUT_NET16(skb, IPSET_ATTR_PORT, data->port);
NLA_PUT_U8(skb, IPSET_ATTR_CIDR2, data->cidr);
- if (data->proto != IPSET_IPPROTO_TCPUDP)
- NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto);
+ NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto);
return 0;
nla_put_failure:
@@ -134,12 +133,11 @@ hash_ipportnet4_data_tlist(struct sk_buff *skb,
const struct hash_ipportnet4_telem *tdata =
(const struct hash_ipportnet4_telem *)data;
- NLA_PUT_NET32(skb, IPSET_ATTR_IP, tdata->ip);
- NLA_PUT_NET32(skb, IPSET_ATTR_IP2, tdata->ip2);
+ NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, tdata->ip);
+ NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP2, tdata->ip2);
NLA_PUT_NET16(skb, IPSET_ATTR_PORT, tdata->port);
NLA_PUT_U8(skb, IPSET_ATTR_CIDR2, data->cidr);
- if (data->proto != IPSET_IPPROTO_TCPUDP)
- NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto);
+ NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto);
NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT,
htonl(ip_set_timeout_get(tdata->timeout)));
@@ -163,8 +161,7 @@ hash_ipportnet4_kadt(struct ip_set *set, const struct sk_buff *skb,
struct chash *h = set->data;
ipset_adtfn adtfn = set->variant->adt[adt];
struct hash_ipportnet4_elem data =
- { .cidr = h->nets[0].cidr || HOST_MASK,
- .proto = h->proto };
+ { .cidr = h->nets[0].cidr || HOST_MASK };
if (data.cidr == 0)
return -EINVAL;
@@ -183,9 +180,9 @@ hash_ipportnet4_kadt(struct ip_set *set, const struct sk_buff *skb,
}
static const struct nla_policy
-hash_ipportnet4_adt_policy[IPSET_ATTR_ADT_MAX + 1] __read_mostly = {
- [IPSET_ATTR_IP] = { .type = NLA_U32 },
- [IPSET_ATTR_IP2] = { .type = NLA_U32 },
+hash_ipportnet_adt_policy[IPSET_ATTR_ADT_MAX + 1] __read_mostly = {
+ [IPSET_ATTR_IP] = { .type = NLA_NESTED },
+ [IPSET_ATTR_IP2] = { .type = NLA_NESTED },
[IPSET_ATTR_PORT] = { .type = NLA_U16 },
[IPSET_ATTR_CIDR2] = { .type = NLA_U8 },
[IPSET_ATTR_PROTO] = { .type = NLA_U8 },
@@ -200,27 +197,24 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *head, int len,
struct chash *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,
- .proto = h->proto };
+ struct hash_ipportnet4_elem data = { .cidr = HOST_MASK };
u32 timeout = h->timeout;
int ret;
if (nla_parse(tb, IPSET_ATTR_ADT_MAX, head, len,
- hash_ipportnet4_adt_policy))
+ hash_ipportnet_adt_policy))
return -IPSET_ERR_PROTOCOL;
if (tb[IPSET_ATTR_LINENO])
*lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
- if (tb[IPSET_ATTR_IP])
- data.ip = ip_set_get_n32(tb[IPSET_ATTR_IP]);
- else
- return -IPSET_ERR_PROTOCOL;
+ ret = ip_set_get_ipaddr4(tb, IPSET_ATTR_IP, &data.ip);
+ if (ret)
+ return ret;
- if (tb[IPSET_ATTR_IP2])
- data.ip2 = ip_set_get_n32(tb[IPSET_ATTR_IP2]);
- else
- return -IPSET_ERR_PROTOCOL;
+ ret = ip_set_get_ipaddr4(tb, IPSET_ATTR_IP2, &data.ip2);
+ if (ret)
+ return ret;
if (tb[IPSET_ATTR_CIDR2])
data.cidr = nla_get_u8(tb[IPSET_ATTR_CIDR2]);
@@ -238,15 +232,15 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *head, int len,
if (tb[IPSET_ATTR_PROTO]) {
data.proto = nla_get_u8(tb[IPSET_ATTR_PROTO]);
- if (data.proto == 0 || data.proto >= IPSET_IPPROTO_TCPUDP)
+ if (data.proto == 0)
return -IPSET_ERR_INVALID_PROTO;
- } else if (data.proto == IPSET_IPPROTO_ANY)
+ } else
return -IPSET_ERR_MISSING_PROTO;
switch (data.proto) {
case IPPROTO_UDP:
case IPPROTO_TCP:
- case IPSET_IPPROTO_TCPUDP:
+ case IPPROTO_ICMP:
break;
default:
data.port = 0;
@@ -259,7 +253,7 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *head, int len,
timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
}
- ret = adtfn(set, &data, GFP_KERNEL, timeout);
+ ret = adtfn(set, &data, GFP_ATOMIC, timeout);
return ip_set_eexist(ret, flags) ? 0 : ret;
}
@@ -273,7 +267,6 @@ hash_ipportnet_same_set(const struct ip_set *a, const struct ip_set *b)
/* Resizing changes htable_bits, so we ignore it */
return x->maxelem == y->maxelem
&& x->timeout == y->timeout
- && x->proto == y->proto
&& x->array_size == y->array_size
&& x->chain_limit == y->chain_limit;
}
@@ -358,12 +351,11 @@ static inline bool
hash_ipportnet6_data_list(struct sk_buff *skb,
const struct hash_ipportnet6_elem *data)
{
- NLA_PUT(skb, IPSET_ATTR_IP, sizeof(struct in6_addr), &data->ip);
- NLA_PUT(skb, IPSET_ATTR_IP2, sizeof(struct in6_addr), &data->ip2);
+ NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP, &data->ip);
+ NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP2, &data->ip2);
NLA_PUT_NET16(skb, IPSET_ATTR_PORT, data->port);
NLA_PUT_U8(skb, IPSET_ATTR_CIDR2, data->cidr);
- if (data->proto != IPSET_IPPROTO_TCPUDP)
- NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto);
+ NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto);
return 0;
nla_put_failure:
@@ -377,12 +369,11 @@ hash_ipportnet6_data_tlist(struct sk_buff *skb,
const struct hash_ipportnet6_telem *e =
(const struct hash_ipportnet6_telem *)data;
- NLA_PUT(skb, IPSET_ATTR_IP, sizeof(struct in6_addr), &e->ip);
- NLA_PUT(skb, IPSET_ATTR_IP2, sizeof(struct in6_addr), &data->ip2);
+ NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP, &e->ip);
+ NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP2, &data->ip2);
NLA_PUT_NET16(skb, IPSET_ATTR_PORT, data->port);
NLA_PUT_U8(skb, IPSET_ATTR_CIDR2, data->cidr);
- if (data->proto != IPSET_IPPROTO_TCPUDP)
- NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto);
+ NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto);
NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT,
htonl(ip_set_timeout_get(e->timeout)));
return 0;
@@ -405,8 +396,7 @@ hash_ipportnet6_kadt(struct ip_set *set, const struct sk_buff *skb,
struct chash *h = set->data;
ipset_adtfn adtfn = set->variant->adt[adt];
struct hash_ipportnet6_elem data =
- { .cidr = h->nets[0].cidr || HOST_MASK,
- .proto = h->proto };
+ { .cidr = h->nets[0].cidr || HOST_MASK };
if (data.cidr == 0)
return -EINVAL;
@@ -424,19 +414,6 @@ hash_ipportnet6_kadt(struct ip_set *set, const struct sk_buff *skb,
return adtfn(set, &data, GFP_ATOMIC, h->timeout);
}
-static const struct nla_policy
-hash_ipportnet6_adt_policy[IPSET_ATTR_ADT_MAX + 1] __read_mostly = {
- [IPSET_ATTR_IP] = { .type = NLA_BINARY,
- .len = sizeof(struct in6_addr) },
- [IPSET_ATTR_IP2] = { .type = NLA_BINARY,
- .len = sizeof(struct in6_addr) },
- [IPSET_ATTR_PORT] = { .type = NLA_U16 },
- [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_ipportnet6_uadt(struct ip_set *set, struct nlattr *head, int len,
enum ipset_adt adt, u32 *lineno, u32 flags)
@@ -444,29 +421,24 @@ hash_ipportnet6_uadt(struct ip_set *set, struct nlattr *head, int len,
struct chash *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,
- .proto = h->proto };
+ struct hash_ipportnet6_elem data = { .cidr = HOST_MASK };
u32 timeout = h->timeout;
int ret;
if (nla_parse(tb, IPSET_ATTR_ADT_MAX, head, len,
- hash_ipportnet6_adt_policy))
+ hash_ipportnet_adt_policy))
return -IPSET_ERR_PROTOCOL;
if (tb[IPSET_ATTR_LINENO])
*lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
- if (tb[IPSET_ATTR_IP])
- memcpy(&data.ip, nla_data(tb[IPSET_ATTR_IP]),
- sizeof(struct in6_addr));
- else
- return -IPSET_ERR_PROTOCOL;
+ ret = ip_set_get_ipaddr6(tb, IPSET_ATTR_IP, &data.ip);
+ if (ret)
+ return ret;
- if (tb[IPSET_ATTR_IP2])
- memcpy(&data.ip2, nla_data(tb[IPSET_ATTR_IP2]),
- sizeof(struct in6_addr));
- else
- return -IPSET_ERR_PROTOCOL;
+ ret = ip_set_get_ipaddr6(tb, IPSET_ATTR_IP2, &data.ip2);
+ if (ret)
+ return ret;
if (tb[IPSET_ATTR_CIDR2])
data.cidr = nla_get_u8(tb[IPSET_ATTR_CIDR2]);
@@ -484,15 +456,15 @@ hash_ipportnet6_uadt(struct ip_set *set, struct nlattr *head, int len,
if (tb[IPSET_ATTR_PROTO]) {
data.proto = nla_get_u8(tb[IPSET_ATTR_PROTO]);
- if (data.proto == 0 || data.proto >= IPSET_IPPROTO_TCPUDP)
+ if (data.proto == 0)
return -IPSET_ERR_INVALID_PROTO;
- } else if (data.proto == IPSET_IPPROTO_ANY)
+ } else
return -IPSET_ERR_MISSING_PROTO;
switch (data.proto) {
case IPPROTO_UDP:
case IPPROTO_TCP:
- case IPSET_IPPROTO_TCPUDP:
+ case IPPROTO_ICMPV6:
break;
default:
data.port = 0;
@@ -505,7 +477,7 @@ hash_ipportnet6_uadt(struct ip_set *set, struct nlattr *head, int len,
timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
}
- ret = adtfn(set, &data, GFP_KERNEL, timeout);
+ ret = adtfn(set, &data, GFP_ATOMIC, timeout);
return ip_set_eexist(ret, flags) ? 0 : ret;
}
@@ -518,7 +490,6 @@ hash_ipportnet_create_policy[IPSET_ATTR_CREATE_MAX+1] __read_mostly = {
[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 },
};
@@ -529,7 +500,6 @@ hash_ipportnet_create(struct ip_set *set, struct nlattr *head,
struct nlattr *tb[IPSET_ATTR_CREATE_MAX+1];
struct chash *h;
u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM;
- u8 proto = IPSET_IPPROTO_TCPUDP; /* Backward compatibility */
if (!(set->family == AF_INET || set->family == AF_INET6))
return -IPSET_ERR_INVALID_FAMILY;
@@ -547,14 +517,9 @@ hash_ipportnet_create(struct ip_set *set, struct nlattr *head,
if (tb[IPSET_ATTR_MAXELEM])
maxelem = ip_set_get_h32(tb[IPSET_ATTR_MAXELEM]);
- if (tb[IPSET_ATTR_PROTO]) {
- proto = nla_get_u8(tb[IPSET_ATTR_PROTO]);
- if (!proto)
- return -IPSET_ERR_INVALID_PROTO;
- }
h = kzalloc(sizeof(*h)
+ sizeof(struct chash_nets)
- * (set->family == AF_INET ? 31 : 127), GFP_KERNEL);
+ * (set->family == AF_INET ? 32 : 128), GFP_KERNEL); h = kzalloc(sizeof(*h), GFP_KERNEL);
if (!h)
return -ENOMEM;
@@ -563,11 +528,11 @@ hash_ipportnet_create(struct ip_set *set, struct nlattr *head,
h->array_size = CHASH_DEFAULT_ARRAY_SIZE;
h->chain_limit = CHASH_DEFAULT_CHAIN_LIMIT;
get_random_bytes(&h->initval, sizeof(h->initval));
- h->proto = proto;
h->timeout = IPSET_NO_TIMEOUT;
- h->htable = ip_set_alloc(jhash_size(h->htable_bits) * sizeof(struct slist),
- GFP_KERNEL);
+ h->htable = ip_set_alloc(
+ jhash_size(h->htable_bits) * sizeof(struct slist),
+ GFP_KERNEL);
if (!h->htable) {
kfree(h);
return -ENOMEM;
@@ -579,7 +544,8 @@ hash_ipportnet_create(struct ip_set *set, struct nlattr *head,
h->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
set->variant = set->family == AF_INET
- ? &hash_ipportnet4_tvariant : &hash_ipportnet6_tvariant;
+ ? &hash_ipportnet4_tvariant
+ : &hash_ipportnet6_tvariant;
if (set->family == AF_INET)
hash_ipportnet4_gc_init(set);
diff --git a/kernel/ip_set_hash_net.c b/kernel/ip_set_hash_net.c
index 6b755ce..27191f2 100644
--- a/kernel/ip_set_hash_net.c
+++ b/kernel/ip_set_hash_net.c
@@ -106,7 +106,7 @@ hash_net4_data_zero_out(struct hash_net4_elem *elem)
static inline bool
hash_net4_data_list(struct sk_buff *skb, const struct hash_net4_elem *data)
{
- NLA_PUT_NET32(skb, IPSET_ATTR_IP, data->ip);
+ NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, data->ip);
NLA_PUT_U8(skb, IPSET_ATTR_CIDR, data->cidr);
return 0;
@@ -120,7 +120,7 @@ hash_net4_data_tlist(struct sk_buff *skb, const struct hash_net4_elem *data)
const struct hash_net4_telem *tdata =
(const struct hash_net4_telem *)data;
- NLA_PUT_NET32(skb, IPSET_ATTR_IP, tdata->ip);
+ NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, tdata->ip);
NLA_PUT_U8(skb, IPSET_ATTR_CIDR, tdata->cidr);
NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT,
htonl(ip_set_timeout_get(tdata->timeout)));
@@ -157,8 +157,8 @@ hash_net4_kadt(struct ip_set *set, const struct sk_buff *skb,
}
static const struct nla_policy
-hash_net4_adt_policy[IPSET_ATTR_ADT_MAX + 1] __read_mostly = {
- [IPSET_ATTR_IP] = { .type = NLA_U32 },
+hash_net_adt_policy[IPSET_ATTR_ADT_MAX + 1] __read_mostly = {
+ [IPSET_ATTR_IP] = { .type = NLA_NESTED },
[IPSET_ATTR_CIDR] = { .type = NLA_U8 },
[IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
};
@@ -175,16 +175,15 @@ hash_net4_uadt(struct ip_set *set, struct nlattr *head, int len,
int ret;
if (nla_parse(tb, IPSET_ATTR_ADT_MAX, head, len,
- hash_net4_adt_policy))
+ hash_net_adt_policy))
return -IPSET_ERR_PROTOCOL;
if (tb[IPSET_ATTR_LINENO])
*lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
- if (tb[IPSET_ATTR_IP])
- data.ip = ip_set_get_n32(tb[IPSET_ATTR_IP]);
- else
- return -IPSET_ERR_PROTOCOL;
+ ret = ip_set_get_ipaddr4(tb, IPSET_ATTR_IP, &data.ip);
+ if (ret)
+ return ret;
if (tb[IPSET_ATTR_CIDR])
data.cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
@@ -200,7 +199,7 @@ hash_net4_uadt(struct ip_set *set, struct nlattr *head, int len,
timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
}
- ret = adtfn(set, &data, GFP_KERNEL, timeout);
+ ret = adtfn(set, &data, GFP_ATOMIC, timeout);
return ip_set_eexist(ret, flags) ? 0 : ret;
}
@@ -292,7 +291,7 @@ hash_net6_data_netmask(struct hash_net6_elem *elem, u8 cidr)
static inline bool
hash_net6_data_list(struct sk_buff *skb, const struct hash_net6_elem *data)
{
- NLA_PUT(skb, IPSET_ATTR_IP, sizeof(struct in6_addr), &data->ip);
+ NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP, &data->ip);
NLA_PUT_U8(skb, IPSET_ATTR_CIDR, data->cidr);
return 0;
@@ -306,7 +305,7 @@ hash_net6_data_tlist(struct sk_buff *skb, const struct hash_net6_elem *data)
const struct hash_net6_telem *e =
(const struct hash_net6_telem *)data;
- NLA_PUT(skb, IPSET_ATTR_IP, sizeof(struct in6_addr), &e->ip);
+ NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP, &e->ip);
NLA_PUT_U8(skb, IPSET_ATTR_CIDR, e->cidr);
NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT,
htonl(ip_set_timeout_get(e->timeout)));
@@ -342,15 +341,6 @@ hash_net6_kadt(struct ip_set *set, const struct sk_buff *skb,
return adtfn(set, &data, GFP_ATOMIC, h->timeout);
}
-static const struct nla_policy
-hash_net6_adt_policy[IPSET_ATTR_ADT_MAX + 1] __read_mostly = {
- [IPSET_ATTR_IP] = { .type = NLA_BINARY,
- .len = sizeof(struct in6_addr) },
- [IPSET_ATTR_CIDR] = { .type = NLA_U8 },
- [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
- [IPSET_ATTR_LINENO] = { .type = NLA_U32 },
-};
-
static int
hash_net6_uadt(struct ip_set *set, struct nlattr *head, int len,
enum ipset_adt adt, u32 *lineno, u32 flags)
@@ -363,17 +353,15 @@ hash_net6_uadt(struct ip_set *set, struct nlattr *head, int len,
int ret;
if (nla_parse(tb, IPSET_ATTR_ADT_MAX, head, len,
- hash_net6_adt_policy))
+ hash_net_adt_policy))
return -IPSET_ERR_PROTOCOL;
if (tb[IPSET_ATTR_LINENO])
*lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
- if (tb[IPSET_ATTR_IP])
- memcpy(&data.ip, nla_data(tb[IPSET_ATTR_IP]),
- sizeof(struct in6_addr));
- else
- return -IPSET_ERR_PROTOCOL;
+ ret = ip_set_get_ipaddr6(tb, IPSET_ATTR_IP, &data.ip);
+ if (ret)
+ return ret;
if (tb[IPSET_ATTR_CIDR])
data.cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
@@ -389,7 +377,7 @@ hash_net6_uadt(struct ip_set *set, struct nlattr *head, int len,
timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
}
- ret = adtfn(set, &data, GFP_KERNEL, timeout);
+ ret = adtfn(set, &data, GFP_ATOMIC, timeout);
return ip_set_eexist(ret, flags) ? 0 : ret;
}
@@ -430,7 +418,7 @@ hash_net_create(struct ip_set *set, struct nlattr *head, int len, u32 flags)
h = kzalloc(sizeof(*h)
+ sizeof(struct chash_nets)
- * (set->family == AF_INET ? 31 : 127), GFP_KERNEL);
+ * (set->family == AF_INET ? 32 : 128), GFP_KERNEL);
if (!h)
return -ENOMEM;
@@ -441,8 +429,9 @@ hash_net_create(struct ip_set *set, struct nlattr *head, int len, u32 flags)
get_random_bytes(&h->initval, sizeof(h->initval));
h->timeout = IPSET_NO_TIMEOUT;
- h->htable = ip_set_alloc(jhash_size(h->htable_bits) * sizeof(struct slist),
- GFP_KERNEL);
+ h->htable = ip_set_alloc(
+ jhash_size(h->htable_bits) * sizeof(struct slist),
+ GFP_KERNEL);
if (!h->htable) {
kfree(h);
return -ENOMEM;
diff --git a/kernel/ip_set_hash_netport.c b/kernel/ip_set_hash_netport.c
new file mode 100644
index 0000000..f7f43b8
--- /dev/null
+++ b/kernel/ip_set_hash_netport.c
@@ -0,0 +1,566 @@
+/* Copyright (C) 2003-2010 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
+ * published by the Free Software Foundation.
+ */
+
+/* Kernel module implementing an IP set type: the hash:net,port type */
+
+#include <linux/netfilter/ip_set_kernel.h>
+#include <linux/netfilter/ip_set_jhash.h>
+#include <linux/module.h>
+#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>
+#include <net/netlink.h>
+#include <net/pfxlen.h>
+
+#include <linux/netfilter.h>
+#include <linux/netfilter/ip_set.h>
+#include <linux/netfilter/ip_set_timeout.h>
+#include <linux/netfilter/ip_set_getport.h>
+#include <linux/netfilter/ip_set_hash.h>
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
+MODULE_DESCRIPTION("hash:net,port type of IP sets");
+MODULE_ALIAS("ip_set_hash:net,port");
+
+/* Type specific function prefix */
+#define TYPE hash_netport
+
+static bool
+hash_netport_same_set(const struct ip_set *a, const struct ip_set *b);
+
+#define hash_netport4_same_set hash_netport_same_set
+#define hash_netport6_same_set hash_netport_same_set
+
+/* The type variant functions: IPv4 */
+
+/* Member elements without timeout */
+struct hash_netport4_elem {
+ u32 ip;
+ u16 port;
+ u8 proto;
+ u8 cidr;
+};
+
+/* Member elements with timeout support */
+struct hash_netport4_telem {
+ u32 ip;
+ u16 port;
+ u8 proto;
+ u8 cidr;
+ unsigned long timeout;
+};
+
+static inline bool
+hash_netport4_data_equal(const struct hash_netport4_elem *ip1,
+ const struct hash_netport4_elem *ip2)
+{
+ return ip1->ip == ip2->ip
+ && ip1->port == ip2->port
+ && ip1->proto == ip2->proto
+ && ip1->cidr == ip2->cidr;
+}
+
+static inline bool
+hash_netport4_data_isnull(const struct hash_netport4_elem *elem)
+{
+ return elem->proto == 0;
+}
+
+static inline void
+hash_netport4_data_copy(struct hash_netport4_elem *dst,
+ const struct hash_netport4_elem *src)
+{
+ dst->ip = src->ip;
+ dst->port = src->port;
+ dst->proto = src->proto;
+ dst->cidr = src->cidr;
+}
+
+static inline void
+hash_netport4_data_swap(struct hash_netport4_elem *dst,
+ struct hash_netport4_elem *src)
+{
+ swap(dst->ip, src->ip);
+ swap(dst->port, src->port);
+ swap(dst->proto, src->proto);
+ swap(dst->cidr, src->cidr);
+}
+
+static inline void
+hash_netport4_data_netmask(struct hash_netport4_elem *elem, u8 cidr)
+{
+ elem->ip &= NETMASK(cidr);
+ elem->cidr = cidr;
+}
+
+static inline void
+hash_netport4_data_zero_out(struct hash_netport4_elem *elem)
+{
+ elem->proto = 0;
+}
+
+static inline bool
+hash_netport4_data_list(struct sk_buff *skb,
+ const struct hash_netport4_elem *data)
+{
+ NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, data->ip);
+ NLA_PUT_NET16(skb, IPSET_ATTR_PORT, data->port);
+ NLA_PUT_U8(skb, IPSET_ATTR_CIDR, data->cidr);
+ NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto);
+ return 0;
+
+nla_put_failure:
+ return 1;
+}
+
+static inline bool
+hash_netport4_data_tlist(struct sk_buff *skb,
+ const struct hash_netport4_elem *data)
+{
+ const struct hash_netport4_telem *tdata =
+ (const struct hash_netport4_telem *)data;
+
+ NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, tdata->ip);
+ NLA_PUT_NET16(skb, IPSET_ATTR_PORT, tdata->port);
+ NLA_PUT_U8(skb, IPSET_ATTR_CIDR, data->cidr);
+ NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto);
+ NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT,
+ htonl(ip_set_timeout_get(tdata->timeout)));
+
+ return 0;
+
+nla_put_failure:
+ return 1;
+}
+
+#define IP_SET_HASH_WITH_PROTO
+#define IP_SET_HASH_WITH_NETS
+
+#define PF 4
+#define HOST_MASK 32
+#include <linux/netfilter/ip_set_chash.h>
+
+static int
+hash_netport4_kadt(struct ip_set *set, const struct sk_buff *skb,
+ enum ipset_adt adt, u8 pf, u8 dim, u8 flags)
+{
+ struct chash *h = set->data;
+ ipset_adtfn adtfn = set->variant->adt[adt];
+ struct hash_netport4_elem data =
+ { .cidr = h->nets[0].cidr || HOST_MASK };
+
+ if (data.cidr == 0)
+ return -EINVAL;
+ if (adt == IPSET_TEST)
+ data.cidr = HOST_MASK;
+
+ if (!get_ip4_port(skb, flags & IPSET_DIM_TWO_SRC,
+ &data.port, &data.proto))
+ return -EINVAL;
+
+ ip4addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip);
+ data.ip &= NETMASK(data.cidr);
+
+ return adtfn(set, &data, GFP_ATOMIC, h->timeout);
+}
+
+static const struct nla_policy
+hash_netport_adt_policy[IPSET_ATTR_ADT_MAX + 1] __read_mostly = {
+ [IPSET_ATTR_IP] = { .type = NLA_NESTED },
+ [IPSET_ATTR_PORT] = { .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,
+ enum ipset_adt adt, u32 *lineno, u32 flags)
+{
+ struct chash *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 timeout = h->timeout;
+ int ret;
+
+ if (nla_parse(tb, IPSET_ATTR_ADT_MAX, head, len,
+ hash_netport_adt_policy))
+ return -IPSET_ERR_PROTOCOL;
+
+ if (tb[IPSET_ATTR_LINENO])
+ *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
+
+ ret = ip_set_get_ipaddr4(tb, IPSET_ATTR_IP, &data.ip);
+ if (ret)
+ return ret;
+
+ if (tb[IPSET_ATTR_CIDR])
+ data.cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
+ if (!data.cidr)
+ return -IPSET_ERR_INVALID_CIDR;
+ data.ip &= NETMASK(data.cidr);
+
+ if (tb[IPSET_ATTR_PORT])
+ data.port = ip_set_get_n16(tb[IPSET_ATTR_PORT]);
+ else
+ return -IPSET_ERR_PROTOCOL;
+
+ if (tb[IPSET_ATTR_PROTO]) {
+ data.proto = nla_get_u8(tb[IPSET_ATTR_PROTO]);
+
+ if (data.proto == 0)
+ return -IPSET_ERR_INVALID_PROTO;
+ } else
+ return -IPSET_ERR_MISSING_PROTO;
+
+ switch (data.proto) {
+ case IPPROTO_UDP:
+ case IPPROTO_TCP:
+ case IPPROTO_ICMP:
+ break;
+ default:
+ data.port = 0;
+ break;
+ }
+
+ if (tb[IPSET_ATTR_TIMEOUT]) {
+ if (!with_timeout(h->timeout))
+ return -IPSET_ERR_TIMEOUT;
+ timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
+ }
+
+ ret = adtfn(set, &data, GFP_ATOMIC, timeout);
+
+ return ip_set_eexist(ret, flags) ? 0 : ret;
+}
+
+static bool
+hash_netport_same_set(const struct ip_set *a, const struct ip_set *b)
+{
+ struct chash *x = a->data;
+ struct chash *y = b->data;
+
+ /* Resizing changes htable_bits, so we ignore it */
+ return x->maxelem == y->maxelem
+ && x->timeout == y->timeout
+ && x->array_size == y->array_size
+ && x->chain_limit == y->chain_limit;
+}
+
+/* The type variant functions: IPv6 */
+
+struct hash_netport6_elem {
+ union nf_inet_addr ip;
+ u16 port;
+ u8 proto;
+ u8 cidr;
+};
+
+struct hash_netport6_telem {
+ union nf_inet_addr ip;
+ u16 port;
+ u8 proto;
+ u8 cidr;
+ unsigned long timeout;
+};
+
+static inline bool
+hash_netport6_data_equal(const struct hash_netport6_elem *ip1,
+ const struct hash_netport6_elem *ip2)
+{
+ return ipv6_addr_cmp(&ip1->ip.in6, &ip2->ip.in6) == 0
+ && ip1->port == ip2->port
+ && ip1->proto == ip2->proto
+ && ip1->cidr == ip2->cidr;
+}
+
+static inline bool
+hash_netport6_data_isnull(const struct hash_netport6_elem *elem)
+{
+ return elem->proto == 0;
+}
+
+static inline void
+hash_netport6_data_copy(struct hash_netport6_elem *dst,
+ const struct hash_netport6_elem *src)
+{
+ memcpy(dst, src, sizeof(*dst));
+}
+
+static inline void
+hash_netport6_data_swap(struct hash_netport6_elem *dst,
+ struct hash_netport6_elem *src)
+{
+ struct hash_netport6_elem tmp;
+
+ memcpy(&tmp, dst, sizeof(tmp));
+ memcpy(dst, src, sizeof(tmp));
+ memcpy(src, &tmp, sizeof(tmp));
+}
+
+static inline void
+hash_netport6_data_zero_out(struct hash_netport6_elem *elem)
+{
+ elem->proto = 0;
+}
+
+static inline void
+ip6_netmask(union nf_inet_addr *ip, u8 prefix)
+{
+ ip->ip6[0] &= NETMASK6(prefix)[0];
+ ip->ip6[1] &= NETMASK6(prefix)[1];
+ ip->ip6[2] &= NETMASK6(prefix)[2];
+ ip->ip6[3] &= NETMASK6(prefix)[3];
+}
+
+static inline void
+hash_netport6_data_netmask(struct hash_netport6_elem *elem, u8 cidr)
+{
+ ip6_netmask(&elem->ip, cidr);
+ elem->cidr = cidr;
+}
+
+static inline bool
+hash_netport6_data_list(struct sk_buff *skb,
+ const struct hash_netport6_elem *data)
+{
+ NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP, &data->ip);
+ NLA_PUT_NET16(skb, IPSET_ATTR_PORT, data->port);
+ NLA_PUT_U8(skb, IPSET_ATTR_CIDR, data->cidr);
+ NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto);
+ return 0;
+
+nla_put_failure:
+ return 1;
+}
+
+static inline bool
+hash_netport6_data_tlist(struct sk_buff *skb,
+ const struct hash_netport6_elem *data)
+{
+ const struct hash_netport6_telem *e =
+ (const struct hash_netport6_telem *)data;
+
+ NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP, &e->ip);
+ NLA_PUT_NET16(skb, IPSET_ATTR_PORT, data->port);
+ NLA_PUT_U8(skb, IPSET_ATTR_CIDR, data->cidr);
+ NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto);
+ NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT,
+ htonl(ip_set_timeout_get(e->timeout)));
+ return 0;
+
+nla_put_failure:
+ return 1;
+}
+
+#undef PF
+#undef HOST_MASK
+
+#define PF 6
+#define HOST_MASK 128
+#include <linux/netfilter/ip_set_chash.h>
+
+static int
+hash_netport6_kadt(struct ip_set *set, const struct sk_buff *skb,
+ enum ipset_adt adt, u8 pf, u8 dim, u8 flags)
+{
+ struct chash *h = set->data;
+ ipset_adtfn adtfn = set->variant->adt[adt];
+ struct hash_netport6_elem data =
+ { .cidr = h->nets[0].cidr || HOST_MASK };
+
+ if (data.cidr == 0)
+ return -EINVAL;
+ if (adt == IPSET_TEST)
+ data.cidr = HOST_MASK;
+
+ if (!get_ip6_port(skb, flags & IPSET_DIM_TWO_SRC,
+ &data.port, &data.proto))
+ return -EINVAL;
+
+ ip6addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip.in6);
+ ip6_netmask(&data.ip, data.cidr);
+
+ return adtfn(set, &data, GFP_ATOMIC, h->timeout);
+}
+
+static int
+hash_netport6_uadt(struct ip_set *set, struct nlattr *head, int len,
+ enum ipset_adt adt, u32 *lineno, u32 flags)
+{
+ struct chash *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 timeout = h->timeout;
+ int ret;
+
+ if (nla_parse(tb, IPSET_ATTR_ADT_MAX, head, len,
+ hash_netport_adt_policy))
+ return -IPSET_ERR_PROTOCOL;
+
+ if (tb[IPSET_ATTR_LINENO])
+ *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
+
+ ret = ip_set_get_ipaddr6(tb, IPSET_ATTR_IP, &data.ip);
+ if (ret)
+ return ret;
+
+ if (tb[IPSET_ATTR_CIDR])
+ data.cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
+ if (!data.cidr)
+ return -IPSET_ERR_INVALID_CIDR;
+ ip6_netmask(&data.ip, data.cidr);
+
+ if (tb[IPSET_ATTR_PORT])
+ data.port = ip_set_get_n16(tb[IPSET_ATTR_PORT]);
+ else
+ return -IPSET_ERR_PROTOCOL;
+
+ if (tb[IPSET_ATTR_PROTO]) {
+ data.proto = nla_get_u8(tb[IPSET_ATTR_PROTO]);
+
+ if (data.proto == 0)
+ return -IPSET_ERR_INVALID_PROTO;
+ } else
+ return -IPSET_ERR_MISSING_PROTO;
+
+ switch (data.proto) {
+ case IPPROTO_UDP:
+ case IPPROTO_TCP:
+ case IPPROTO_ICMPV6:
+ break;
+ default:
+ data.port = 0;
+ break;
+ }
+
+ if (tb[IPSET_ATTR_TIMEOUT]) {
+ if (!with_timeout(h->timeout))
+ return -IPSET_ERR_TIMEOUT;
+ timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
+ }
+
+ ret = adtfn(set, &data, GFP_ATOMIC, timeout);
+
+ return ip_set_eexist(ret, flags) ? 0 : ret;
+}
+
+/* Create hash:ip type of sets */
+
+static const struct nla_policy
+hash_netport_create_policy[IPSET_ATTR_CREATE_MAX+1] __read_mostly = {
+ [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)
+{
+ struct nlattr *tb[IPSET_ATTR_CREATE_MAX+1];
+ struct chash *h;
+ u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM;
+
+ 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 (tb[IPSET_ATTR_HASHSIZE]) {
+ hashsize = ip_set_get_h32(tb[IPSET_ATTR_HASHSIZE]);
+ if (hashsize < IPSET_MIMINAL_HASHSIZE)
+ hashsize = IPSET_MIMINAL_HASHSIZE;
+ }
+
+ if (tb[IPSET_ATTR_MAXELEM])
+ maxelem = ip_set_get_h32(tb[IPSET_ATTR_MAXELEM]);
+
+ h = kzalloc(sizeof(*h)
+ + sizeof(struct chash_nets)
+ * (set->family == AF_INET ? 32 : 128), GFP_KERNEL);
+ if (!h)
+ return -ENOMEM;
+
+ h->maxelem = maxelem;
+ h->htable_bits = htable_bits(hashsize);
+ h->array_size = CHASH_DEFAULT_ARRAY_SIZE;
+ h->chain_limit = CHASH_DEFAULT_CHAIN_LIMIT;
+ get_random_bytes(&h->initval, sizeof(h->initval));
+ h->timeout = IPSET_NO_TIMEOUT;
+
+ h->htable = ip_set_alloc(
+ jhash_size(h->htable_bits) * sizeof(struct slist),
+ GFP_KERNEL);
+ if (!h->htable) {
+ kfree(h);
+ return -ENOMEM;
+ }
+
+ set->data = h;
+
+ if (tb[IPSET_ATTR_TIMEOUT]) {
+ h->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
+
+ set->variant = set->family == AF_INET
+ ? &hash_netport4_tvariant : &hash_netport6_tvariant;
+
+ if (set->family == AF_INET)
+ hash_netport4_gc_init(set);
+ else
+ hash_netport6_gc_init(set);
+ } else {
+ set->variant = set->family == AF_INET
+ ? &hash_netport4_variant : &hash_netport6_variant;
+ }
+
+ pr_debug("create %s hashsize %u (%u) maxelem %u: %p(%p)",
+ set->name, jhash_size(h->htable_bits),
+ h->htable_bits, h->maxelem, set->data, h->htable);
+
+ return 0;
+}
+
+static struct ip_set_type hash_netport_type = {
+ .name = "hash:net,port",
+ .protocol = IPSET_PROTOCOL,
+ .features = IPSET_TYPE_IP | IPSET_TYPE_PORT,
+ .dimension = IPSET_DIM_TWO,
+ .family = AF_UNSPEC,
+ .revision = 0,
+ .create = hash_netport_create,
+ .me = THIS_MODULE,
+};
+
+static int __init
+hash_netport_init(void)
+{
+ return ip_set_type_register(&hash_netport_type);
+}
+
+static void __exit
+hash_netport_fini(void)
+{
+ ip_set_type_unregister(&hash_netport_type);
+}
+
+module_init(hash_netport_init);
+module_exit(hash_netport_fini);
diff --git a/kernel/ip_set_list_set.c b/kernel/ip_set_list_set.c
index c1e4699..ea3f0a9 100644
--- a/kernel/ip_set_list_set.c
+++ b/kernel/ip_set_list_set.c
@@ -250,7 +250,8 @@ list_set_uadt(struct ip_set *set, struct nlattr *head, int len,
}
if (tb[IPSET_ATTR_NAMEREF]) {
- refid = ip_set_get_byname(nla_data(tb[IPSET_ATTR_NAMEREF]), &s);
+ refid = ip_set_get_byname(nla_data(tb[IPSET_ATTR_NAMEREF]),
+ &s);
if (refid == IPSET_INVALID_ID) {
ret = -IPSET_ERR_NAMEREF;
goto finish;
@@ -320,7 +321,8 @@ list_set_uadt(struct ip_set *set, struct nlattr *head, int len,
continue;
else if (elem->id == id
&& (before == 0
- || (before > 0 && next_id_eq(map, i, refid))))
+ || (before > 0
+ && next_id_eq(map, i, refid))))
ret = list_set_del(map, id, i);
else if (before < 0 && elem->id == refid
&& next_id_eq(map, i, id))