From 4902415c1e95003068343d69206887be0e202615 Mon Sep 17 00:00:00 2001 From: Jozsef Kadlecsik Date: Tue, 7 Dec 2010 17:46:40 +0100 Subject: Create include/linux/netfilter/ipset/ directory Separate the ipset header files from netfilter header files. --- kernel/include/linux/netfilter/ip_set.h | 526 --------- kernel/include/linux/netfilter/ip_set_bitmap.h | 31 - kernel/include/linux/netfilter/ip_set_chash.h | 1164 -------------------- kernel/include/linux/netfilter/ip_set_getport.h | 126 --- kernel/include/linux/netfilter/ip_set_hash.h | 26 - kernel/include/linux/netfilter/ip_set_jhash.h | 121 -- kernel/include/linux/netfilter/ip_set_kernel.h | 15 - kernel/include/linux/netfilter/ip_set_list.h | 27 - kernel/include/linux/netfilter/ip_set_slist.h | 89 -- kernel/include/linux/netfilter/ip_set_timeout.h | 127 --- kernel/include/linux/netfilter/ipset/ip_set.h | 526 +++++++++ .../include/linux/netfilter/ipset/ip_set_bitmap.h | 31 + .../include/linux/netfilter/ipset/ip_set_chash.h | 1164 ++++++++++++++++++++ .../include/linux/netfilter/ipset/ip_set_getport.h | 126 +++ kernel/include/linux/netfilter/ipset/ip_set_hash.h | 26 + .../include/linux/netfilter/ipset/ip_set_jhash.h | 121 ++ .../include/linux/netfilter/ipset/ip_set_kernel.h | 15 + kernel/include/linux/netfilter/ipset/ip_set_list.h | 27 + .../include/linux/netfilter/ipset/ip_set_slist.h | 89 ++ .../include/linux/netfilter/ipset/ip_set_timeout.h | 127 +++ kernel/include/linux/netfilter/xt_set.h | 2 +- 21 files changed, 2253 insertions(+), 2253 deletions(-) delete mode 100644 kernel/include/linux/netfilter/ip_set.h delete mode 100644 kernel/include/linux/netfilter/ip_set_bitmap.h delete mode 100644 kernel/include/linux/netfilter/ip_set_chash.h delete mode 100644 kernel/include/linux/netfilter/ip_set_getport.h delete mode 100644 kernel/include/linux/netfilter/ip_set_hash.h delete mode 100644 kernel/include/linux/netfilter/ip_set_jhash.h delete mode 100644 kernel/include/linux/netfilter/ip_set_kernel.h delete mode 100644 kernel/include/linux/netfilter/ip_set_list.h delete mode 100644 kernel/include/linux/netfilter/ip_set_slist.h delete mode 100644 kernel/include/linux/netfilter/ip_set_timeout.h create mode 100644 kernel/include/linux/netfilter/ipset/ip_set.h create mode 100644 kernel/include/linux/netfilter/ipset/ip_set_bitmap.h create mode 100644 kernel/include/linux/netfilter/ipset/ip_set_chash.h create mode 100644 kernel/include/linux/netfilter/ipset/ip_set_getport.h create mode 100644 kernel/include/linux/netfilter/ipset/ip_set_hash.h create mode 100644 kernel/include/linux/netfilter/ipset/ip_set_jhash.h create mode 100644 kernel/include/linux/netfilter/ipset/ip_set_kernel.h create mode 100644 kernel/include/linux/netfilter/ipset/ip_set_list.h create mode 100644 kernel/include/linux/netfilter/ipset/ip_set_slist.h create mode 100644 kernel/include/linux/netfilter/ipset/ip_set_timeout.h (limited to 'kernel/include') diff --git a/kernel/include/linux/netfilter/ip_set.h b/kernel/include/linux/netfilter/ip_set.h deleted file mode 100644 index 1e18b14..0000000 --- a/kernel/include/linux/netfilter/ip_set.h +++ /dev/null @@ -1,526 +0,0 @@ -#ifndef _IP_SET_H -#define _IP_SET_H - -/* Copyright (C) 2000-2002 Joakim Axelsson - * Patrick Schaaf - * Martin Josefsson - * Copyright (C) 2003-2010 Jozsef Kadlecsik - * - * 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. - */ - -/* The protocol version */ -#define IPSET_PROTOCOL 5 - -/* The max length of strings including NUL: set and type identifiers */ -#define IPSET_MAXNAMELEN 32 - -/* Message types and commands */ -enum ipset_cmd { - IPSET_CMD_NONE, - IPSET_CMD_PROTOCOL, /* 1: Return protocol version */ - IPSET_CMD_CREATE, /* 2: Create a new (empty) set */ - IPSET_CMD_DESTROY, /* 3: Destroy a (empty) set */ - IPSET_CMD_FLUSH, /* 4: Remove all elements from a set */ - IPSET_CMD_RENAME, /* 5: Rename a set */ - IPSET_CMD_SWAP, /* 6: Swap two sets */ - IPSET_CMD_LIST, /* 7: List sets */ - IPSET_CMD_SAVE, /* 8: Save sets */ - IPSET_CMD_ADD, /* 9: Add an element to a set */ - IPSET_CMD_DEL, /* 10: Delete an element from a set */ - IPSET_CMD_TEST, /* 11: Test an element in a set */ - IPSET_CMD_HEADER, /* 12: Get set header data only */ - IPSET_CMD_TYPE, /* 13: Get set type */ - IPSET_MSG_MAX, /* Netlink message commands */ - - /* Commands in userspace: */ - IPSET_CMD_RESTORE = IPSET_MSG_MAX, /* 14: Enter restore mode */ - IPSET_CMD_HELP, /* 15: Get help */ - IPSET_CMD_VERSION, /* 16: Get program version */ - IPSET_CMD_QUIT, /* 17: Quit from interactive mode */ - - IPSET_CMD_MAX, - - IPSET_CMD_COMMIT = IPSET_CMD_MAX, /* 18: Commit buffered commands */ -}; - -/* Attributes at command level */ -enum { - IPSET_ATTR_UNSPEC, - 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, /* Setname at rename/swap */ - IPSET_ATTR_REVISION, /* 4: Settype revision */ - IPSET_ATTR_FAMILY, /* 5: Settype family */ - IPSET_ATTR_FLAGS, /* 6: Flags at command level */ - IPSET_ATTR_DATA, /* 7: Nested attributes */ - IPSET_ATTR_ADT, /* 8: Multiple data containers */ - IPSET_ATTR_LINENO, /* 9: Restore lineno */ - IPSET_ATTR_PROTOCOL_MIN, /* 10: Minimal supported version number */ - IPSET_ATTR_REVISION_MIN = IPSET_ATTR_PROTOCOL_MIN, /* type rev min */ - __IPSET_ATTR_CMD_MAX, -}; -#define IPSET_ATTR_CMD_MAX (__IPSET_ATTR_CMD_MAX - 1) - -/* CADT specific attributes */ -enum { - IPSET_ATTR_IP = IPSET_ATTR_UNSPEC + 1, - IPSET_ATTR_IP_FROM = IPSET_ATTR_IP, - IPSET_ATTR_IP_TO, /* 2 */ - IPSET_ATTR_CIDR, /* 3 */ - IPSET_ATTR_PORT, /* 4 */ - IPSET_ATTR_PORT_FROM = IPSET_ATTR_PORT, - IPSET_ATTR_PORT_TO, /* 5 */ - IPSET_ATTR_TIMEOUT, /* 6 */ - IPSET_ATTR_PROTO, /* 7 */ - IPSET_ATTR_CADT_FLAGS, /* 8 */ - IPSET_ATTR_CADT_LINENO = IPSET_ATTR_LINENO, /* 9 */ - /* Reserve empty slots */ - IPSET_ATTR_CADT_MAX = 16, - /* Create-only specific attributes */ - IPSET_ATTR_GC, - IPSET_ATTR_HASHSIZE, - IPSET_ATTR_MAXELEM, - IPSET_ATTR_NETMASK, - IPSET_ATTR_PROBES, - IPSET_ATTR_RESIZE, - IPSET_ATTR_SIZE, - /* Kernel-only */ - IPSET_ATTR_ELEMENTS, - IPSET_ATTR_REFERENCES, - IPSET_ATTR_MEMSIZE, - - __IPSET_ATTR_CREATE_MAX, -}; -#define IPSET_ATTR_CREATE_MAX (__IPSET_ATTR_CREATE_MAX - 1) - -/* ADT specific attributes */ -enum { - IPSET_ATTR_ETHER = IPSET_ATTR_CADT_MAX + 1, - IPSET_ATTR_NAME, - IPSET_ATTR_NAMEREF, - IPSET_ATTR_IP2, - IPSET_ATTR_CIDR2, - __IPSET_ATTR_ADT_MAX, -}; -#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, - IPSET_ERR_PROTOCOL, - IPSET_ERR_FIND_TYPE, - IPSET_ERR_MAX_SETS, - IPSET_ERR_BUSY, - IPSET_ERR_EXIST_SETNAME2, - IPSET_ERR_TYPE_MISMATCH, - IPSET_ERR_EXIST, - IPSET_ERR_INVALID_CIDR, - IPSET_ERR_INVALID_NETMASK, - 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), -}; - -/* Commands with settype-specific attributes */ -enum ipset_adt { - IPSET_ADD, - IPSET_DEL, - IPSET_TEST, - IPSET_ADT_MAX, - IPSET_CREATE = IPSET_ADT_MAX, - IPSET_CADT_MAX, -}; - -#ifdef __KERNEL__ -#include -#include -#include -#include -#include -#include - -/* Sets are identified by an index in kernel space. Tweak with ip_set_id_t - * and IPSET_INVALID_ID if you want to increase the max number of sets. - */ -typedef u16 ip_set_id_t; - -#define IPSET_INVALID_ID 65535 - -enum ip_set_dim { - IPSET_DIM_ZERO = 0, - IPSET_DIM_ONE, - IPSET_DIM_TWO, - IPSET_DIM_THREE, - /* Max dimension in elements. - * If changed, new revision of iptables match/target is required. - */ - IPSET_DIM_MAX = 6, -}; - -/* Option flags for kernel operations */ -enum ip_set_kopt { - IPSET_INV_MATCH = (1 << IPSET_DIM_ZERO), - IPSET_DIM_ONE_SRC = (1 << IPSET_DIM_ONE), - IPSET_DIM_TWO_SRC = (1 << IPSET_DIM_TWO), - IPSET_DIM_THREE_SRC = (1 << IPSET_DIM_THREE), -}; - -/* Set features */ -enum ip_set_feature { - IPSET_TYPE_IP_FLAG = 0, - IPSET_TYPE_IP = (1 << IPSET_TYPE_IP_FLAG), - IPSET_TYPE_PORT_FLAG = 1, - IPSET_TYPE_PORT = (1 << IPSET_TYPE_PORT_FLAG), - IPSET_TYPE_MAC_FLAG = 2, - IPSET_TYPE_MAC = (1 << IPSET_TYPE_MAC_FLAG), - IPSET_TYPE_IP2_FLAG = 3, - IPSET_TYPE_IP2 = (1 << IPSET_TYPE_IP2_FLAG), - IPSET_TYPE_NAME_FLAG = 4, - IPSET_TYPE_NAME = (1 << IPSET_TYPE_NAME_FLAG), - /* 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), -}; - -struct ip_set; - -typedef int (*ipset_adtfn)(struct ip_set *set, void *value, - gfp_t gfp_flags, u32 timeout); - -/* Set type, variant-specific part */ -struct ip_set_type_variant { - /* Kernelspace: test/add/del entries */ - int (*kadt)(struct ip_set *set, const struct sk_buff * skb, - enum ipset_adt adt, u8 pf, u8 dim, u8 flags); - - /* Userspace: test/add/del entries */ - int (*uadt)(struct ip_set *set, struct nlattr *head, int len, - enum ipset_adt adt, u32 *lineno, u32 flags); - - /* Low level add/del/test functions */ - ipset_adtfn adt[IPSET_ADT_MAX]; - - /* When adding entries and set is full, try to resize the set */ - int (*resize)(struct ip_set *set, gfp_t gfp_flags, bool retried); - /* Destroy the set */ - void (*destroy)(struct ip_set *set); - /* Flush the elements */ - void (*flush)(struct ip_set *set); - /* Expire entries before listing */ - void (*expire)(struct ip_set *set); - /* List set header data */ - int (*head)(struct ip_set *set, struct sk_buff *skb); - /* List elements */ - int (*list)(struct ip_set *set, struct sk_buff *skb, - struct netlink_callback *cb); - - /* Return true if "b" set is the same as "a" - * according to the create set parameters */ - bool (*same_set)(const struct ip_set *a, const struct ip_set *b); -}; - -/* The core set type structure */ -struct ip_set_type { - struct list_head list; - - /* Typename */ - char name[IPSET_MAXNAMELEN]; - /* Protocol version */ - u8 protocol; - /* Set features to control swapping */ - u8 features; - /* Set type dimension */ - u8 dimension; - /* Supported family: may be AF_UNSPEC for both AF_INET/AF_INET6 */ - u8 family; - /* Type revision */ - u8 revision; - - /* Create set */ - int (*create)(struct ip_set *set, - struct nlattr *head, int len, u32 flags); - - /* Set this to THIS_MODULE if you are a module, otherwise NULL */ - struct module *me; -}; - -extern int ip_set_type_register(struct ip_set_type *set_type); -extern void ip_set_type_unregister(struct ip_set_type *set_type); - -/* A generic IP set */ -struct ip_set { - /* The name of the set */ - char name[IPSET_MAXNAMELEN]; - /* Lock protecting the set data */ - rwlock_t lock; - /* References to the set */ - atomic_t ref; - /* The core set type */ - const struct ip_set_type *type; - /* The type variant doing the real job */ - const struct ip_set_type_variant *variant; - /* The actual INET family of the set */ - u8 family; - /* The type specific data */ - void *data; -}; - -/* register and unregister set references */ -extern ip_set_id_t ip_set_get_byname(const char *name, struct ip_set **set); -extern void ip_set_put_byindex(ip_set_id_t index); -extern const char * ip_set_name_byindex(ip_set_id_t index); -extern ip_set_id_t ip_set_nfnl_get(const char *name); -extern ip_set_id_t ip_set_nfnl_get_byindex(ip_set_id_t index); -extern void ip_set_nfnl_put(ip_set_id_t index); - -/* API for iptables set match, and SET target */ -extern int ip_set_add(ip_set_id_t id, const struct sk_buff *skb, - u8 family, u8 dim, u8 flags); -extern int ip_set_del(ip_set_id_t id, const struct sk_buff *skb, - u8 family, u8 dim, u8 flags); -extern int ip_set_test(ip_set_id_t id, const struct sk_buff *skb, - u8 family, u8 dim, u8 flags); - -/* Allocate members */ -static inline void * -ip_set_alloc(size_t size, gfp_t gfp_mask) -{ - void *members = NULL; - - if (size < KMALLOC_MAX_SIZE) - members = kzalloc(size, gfp_mask | __GFP_NOWARN); - - if (members) { - pr_debug("%p: allocated with kmalloc", members); - return members; - } - - members = __vmalloc(size, gfp_mask | __GFP_ZERO, PAGE_KERNEL); - if (!members) - return NULL; - pr_debug("%p: allocated with vmalloc", members); - - return members; -} - -static inline void -ip_set_free(void *members) -{ - pr_debug("%p: free with %s", members, - is_vmalloc_addr(members) ? "vfree" : "kfree"); - if (is_vmalloc_addr(members)) - vfree(members); - else - kfree(members); -} - -/* Ignore IPSET_ERR_EXIST errors if asked to do so? */ -static inline bool -ip_set_eexist(int ret, u32 flags) -{ - return ret == -IPSET_ERR_EXIST && (flags & IPSET_FLAG_EXIST); -} - -/* Useful converters */ -static inline u32 -ip_set_get_h32(const struct nlattr *attr) -{ - u32 value = nla_get_u32(attr); - - return attr->nla_type & NLA_F_NET_BYTEORDER ? ntohl(value) : value; -} - -static inline u16 -ip_set_get_h16(const struct nlattr *attr) -{ - u16 value = nla_get_u16(attr); - - return attr->nla_type & NLA_F_NET_BYTEORDER ? ntohs(value) : value; -} - -static inline u32 -ip_set_get_n32(const struct nlattr *attr) -{ - u32 value = nla_get_u32(attr); - - return attr->nla_type & NLA_F_NET_BYTEORDER ? value : htonl(value); -} - -static inline u16 -ip_set_get_n16(const struct nlattr *attr) -{ - u16 value = nla_get_u16(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) - -#define NLA_PUT_NET32(skb, type, value) \ - NLA_PUT_BE32(skb, type | NLA_F_NET_BYTEORDER, value) - -#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) -{ - return src ? ip_hdr(skb)->saddr : ip_hdr(skb)->daddr; -} - -static inline void -ip4addrptr(const struct sk_buff *skb, bool src, u32 *addr) -{ - *addr = src ? ip_hdr(skb)->saddr : ip_hdr(skb)->daddr; -} - -static inline void -ip6addrptr(const struct sk_buff *skb, bool src, struct in6_addr *addr) -{ - memcpy(addr, src ? &ipv6_hdr(skb)->saddr : &ipv6_hdr(skb)->daddr, - sizeof(*addr)); -} - -/* Calculate the bytes required to store the inclusive range of a-b */ -static inline int -bitmap_bytes(u32 a, u32 b) -{ - return 4 * ((((b - a + 8) / 8) + 3) / 4); -} - -/* Prefixlen maps */ -extern const union nf_inet_addr prefixlen_netmask_map[]; -extern const union nf_inet_addr prefixlen_hostmask_map[]; - -#define NETMASK(n) prefixlen_netmask_map[n].ip -#define NETMASK6(n) prefixlen_netmask_map[n].ip6 -#define HOSTMASK(n) prefixlen_hostmask_map[n].ip -#define HOSTMASK6(n) prefixlen_hostmask_map[n].ip6 - -/* Interface to iptables/ip6tables */ - -#define SO_IP_SET 83 - -union ip_set_name_index { - char name[IPSET_MAXNAMELEN]; - ip_set_id_t index; -}; - -#define IP_SET_OP_GET_BYNAME 0x00000006 /* Get set index by name */ -struct ip_set_req_get_set { - unsigned op; - unsigned version; - union ip_set_name_index set; -}; - -#define IP_SET_OP_GET_BYINDEX 0x00000007 /* Get set name by index */ -/* Uses ip_set_req_get_set */ - -#define IP_SET_OP_VERSION 0x00000100 /* Ask kernel version */ -struct ip_set_req_version { - unsigned op; - unsigned version; -}; - -#endif /* __KERNEL__ */ - -#endif /*_IP_SET_H */ diff --git a/kernel/include/linux/netfilter/ip_set_bitmap.h b/kernel/include/linux/netfilter/ip_set_bitmap.h deleted file mode 100644 index 61a9e87..0000000 --- a/kernel/include/linux/netfilter/ip_set_bitmap.h +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef __IP_SET_BITMAP_H -#define __IP_SET_BITMAP_H - -/* 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, -}; - -#ifdef __KERNEL__ -#define IPSET_BITMAP_MAX_RANGE 0x0000FFFF - -/* Common functions */ - -static inline u32 -range_to_mask(u32 from, u32 to, u8 *bits) -{ - u32 mask = 0xFFFFFFFE; - - *bits = 32; - while (--(*bits) > 0 && mask && (to & mask) != from) - mask <<= 1; - - return mask; -} - -#endif /* __KERNEL__ */ - -#endif /* __IP_SET_BITMAP_H */ diff --git a/kernel/include/linux/netfilter/ip_set_chash.h b/kernel/include/linux/netfilter/ip_set_chash.h deleted file mode 100644 index 138e94d..0000000 --- a/kernel/include/linux/netfilter/ip_set_chash.h +++ /dev/null @@ -1,1164 +0,0 @@ -#ifndef _IP_SET_CHASH_H -#define _IP_SET_CHASH_H - -#include -#include -#include - -/* 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 */ -#define CHASH_DEFAULT_ARRAY_SIZE 4 -/* 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 */ -}; - -struct htable { - u8 htable_bits; /* size of hash table == 2^htable_bits */ - struct slist htable[0]; /* hashtable of single linked lists */ -}; - -struct chash { - struct htable *table; /* the hash table */ - u32 maxelem; /* max elements in the hash */ - u32 elements; /* current element (vs timeout) */ - u32 initval; /* random jhash init value */ - u32 timeout; /* timeout value, if enabled */ - struct timer_list gc; /* garbage collection when timeout enabled */ - u8 array_size; /* number of elements in an array */ - u8 chain_limit; /* max number of arrays */ -#ifdef IP_SET_HASH_WITH_NETMASK - u8 netmask; /* netmask value for subnets to store */ -#endif -#ifdef IP_SET_HASH_WITH_NETS - 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) -{ - /* Assume that hashsize == 2^htable_bits */ - u8 bits = fls(hashsize - 1); - if (jhash_size(bits) != hashsize) - /* Round up to the first 2^n value */ - bits = fls(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 *h, u8 cidr, u8 host_mask) -{ - u8 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 (h->nets[i].cidr < cidr) - swap(h->nets[i].cidr, cidr); - } - if (i < host_mask) - h->nets[i].cidr = cidr; -} - -static inline void -del_cidr(struct chash *h, u8 cidr, u8 host_mask) -{ - u8 i; - - --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; - } - h->nets[i - 1].cidr = 0; -} -#endif - -/* Destroy the hashtable part of the set */ -static void -chash_destroy(struct htable *ht) -{ - struct slist *n, *tmp; - u32 i; - - for (i = 0; i < jhash_size(ht->htable_bits); i++) - slist_for_each_safe(n, tmp, &ht->htable[i]) - /* FIXME: use slab cache */ - kfree(n); - - ip_set_free(ht); -} - -/* Calculate the actual memory size of the set data */ -static size_t -chash_memsize(const struct chash *h, size_t dsize, u8 host_mask) -{ - struct slist *n; - u32 i; - struct htable *ht = h->table; - size_t memsize = sizeof(*h) -#ifdef IP_SET_HASH_WITH_NETS - + sizeof(struct chash_nets) * host_mask -#endif - + jhash_size(ht->htable_bits) * sizeof(struct slist); - - for (i = 0; i < jhash_size(ht->htable_bits); i++) - slist_for_each(n, &ht->htable[i]) - memsize += sizeof(struct slist) - + h->array_size * dsize; - - return memsize; -} - -/* Flush a hash type of set: destroy all elements */ -static void -ip_set_hash_flush(struct ip_set *set) -{ - struct chash *h = set->data; - struct htable *ht = h->table; - struct slist *n, *tmp; - u32 i; - - for (i = 0; i < jhash_size(ht->htable_bits); i++) { - slist_for_each_safe(n, tmp, &ht->htable[i]) - /* FIXME: slab cache */ - kfree(n); - ht->htable[i].next = NULL; - } -#ifdef IP_SET_HASH_WITH_NETS - memset(h->nets, 0, sizeof(struct chash_nets) - * 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) -{ - struct chash *h = set->data; - - if (with_timeout(h->timeout)) - del_timer_sync(&h->gc); - - chash_destroy(h->table); - kfree(h); - - set->data = NULL; -} - -#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) -#define type_pf_data_isnull TOKEN(TYPE, PF, _data_isnull) -#define type_pf_data_copy TOKEN(TYPE, PF, _data_copy) -#define type_pf_data_swap TOKEN(TYPE, PF, _data_swap) -#define type_pf_data_zero_out TOKEN(TYPE, PF, _data_zero_out) -#define type_pf_data_netmask TOKEN(TYPE, PF, _data_netmask) -#define type_pf_data_list TOKEN(TYPE, PF, _data_list) -#define type_pf_data_tlist TOKEN(TYPE, PF, _data_tlist) - -#define type_pf_elem TOKEN(TYPE, PF, _elem) -#define type_pf_telem TOKEN(TYPE, PF, _telem) -#define type_pf_data_timeout TOKEN(TYPE, PF, _data_timeout) -#define type_pf_data_expired TOKEN(TYPE, PF, _data_expired) -#define type_pf_data_swap_timeout TOKEN(TYPE, PF, _data_swap_timeout) -#define type_pf_data_timeout_set TOKEN(TYPE, PF, _data_timeout_set) - -#define type_pf_chash_readd TOKEN(TYPE, PF, _chash_readd) -#define type_pf_chash_del_elem TOKEN(TYPE, PF, _chash_del_elem) -#define type_pf_chash_add TOKEN(TYPE, PF, _chash_add) -#define type_pf_chash_del TOKEN(TYPE, PF, _chash_del) -#define type_pf_chash_test_cidrs TOKEN(TYPE, PF, _chash_test_cidrs) -#define type_pf_chash_test TOKEN(TYPE, PF, _chash_test) - -#define type_pf_chash_treadd TOKEN(TYPE, PF, _chash_treadd) -#define type_pf_chash_del_telem TOKEN(TYPE, PF, _chash_del_telem) -#define type_pf_chash_expire TOKEN(TYPE, PF, _chash_expire) -#define type_pf_chash_tadd TOKEN(TYPE, PF, _chash_tadd) -#define type_pf_chash_tdel TOKEN(TYPE, PF, _chash_tdel) -#define type_pf_chash_ttest_cidrs TOKEN(TYPE, PF, _chash_ttest_cidrs) -#define type_pf_chash_ttest TOKEN(TYPE, PF, _chash_ttest) - -#define type_pf_resize TOKEN(TYPE, PF, _resize) -#define type_pf_tresize TOKEN(TYPE, PF, _tresize) -#define type_pf_flush ip_set_hash_flush -#define type_pf_destroy ip_set_hash_destroy -#define type_pf_head TOKEN(TYPE, PF, _head) -#define type_pf_list TOKEN(TYPE, PF, _list) -#define type_pf_tlist TOKEN(TYPE, PF, _tlist) -#define type_pf_same_set TOKEN(TYPE, PF, _same_set) -#define type_pf_kadt TOKEN(TYPE, PF, _kadt) -#define type_pf_uadt TOKEN(TYPE, PF, _uadt) -#define type_pf_gc TOKEN(TYPE, PF, _gc) -#define type_pf_gc_init TOKEN(TYPE, PF, _gc_init) -#define type_pf_variant TOKEN(TYPE, PF, _variant) -#define type_pf_tvariant TOKEN(TYPE, PF, _tvariant) - -/* 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 htable *ht, - const struct type_pf_elem *value, - gfp_t gfp_flags) -{ - struct slist *n, *prev; - struct type_pf_elem *data; - void *tmp; - int i = 0, j = 0; - u32 hash = JHASH2(value, h->initval, ht->htable_bits); - - slist_for_each_prev(prev, n, &ht->htable[hash]) { - for (i = 0; i < h->array_size; i++) { - data = chash_data(n, i); - if (type_pf_data_isnull(data)) { - tmp = n; - goto found; - } - } - j++; - } - if (j < h->chain_limit) { - tmp = kzalloc(h->array_size * sizeof(struct type_pf_elem) - + sizeof(struct slist), gfp_flags); - if (!tmp) - return -ENOMEM; - prev->next = (struct slist *) tmp; - data = chash_data(tmp, 0); - } else { - /* Trigger rehashing */ - return -EAGAIN; - } -found: - type_pf_data_copy(data, value); - 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; /* Index in array */ - - if (n->next != NULL) { - for (prev = n, tmp = n->next; - tmp->next != NULL; - prev = tmp, tmp = tmp->next) - /* Find last array */; - j = 0; - } else { - /* Already at last array */ - tmp = n; - j = i; - } - /* Find last non-empty element */ - for (; j < h->array_size - 1; j++) - if (type_pf_data_isnull(chash_data(tmp, j + 1))) - break; - - if (!(tmp == n && i == j)) - type_pf_data_swap(data, chash_data(tmp, j)); - -#ifdef IP_SET_HASH_WITH_NETS - del_cidr(h, data->cidr, HOST_MASK); -#endif - if (j == 0) { - prev->next = NULL; - kfree(tmp); - } else - type_pf_data_zero_out(chash_data(tmp, j)); - - 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) -{ - struct chash *h = set->data; - struct htable *ht, *orig = h->table; - u8 htable_bits = orig->htable_bits; - struct slist *n; - const struct type_pf_elem *data; - u32 i, j; - int ret; - -retry: - ret = i = 0; - htable_bits++; - if (!htable_bits) - /* In case we have plenty of memory :-) */ - return -IPSET_ERR_HASH_FULL; - ht = ip_set_alloc(sizeof(*ht) - + jhash_size(htable_bits) * sizeof(struct slist), - GFP_KERNEL); - if (!ht) - return -ENOMEM; - ht->htable_bits = htable_bits; - - read_lock_bh(&set->lock); -next_slot: - for (; i < jhash_size(orig->htable_bits); i++) { - slist_for_each(n, &orig->htable[i]) { - for (j = 0; j < h->array_size; j++) { - data = chash_data(n, j); - if (type_pf_data_isnull(data)) { - i++; - goto next_slot; - } - ret = type_pf_chash_readd(h, ht, - data, gfp_flags); - if (ret < 0) { - read_unlock_bh(&set->lock); - chash_destroy(ht); - if (ret == -EAGAIN) - goto retry; - return ret; - } - } - } - } - - h->table = ht; - read_unlock_bh(&set->lock); - - /* Give time to other users of the set */ - synchronize_net(); - - chash_destroy(orig); - - 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) -{ - struct chash *h = set->data; - const struct type_pf_elem *d = value; - struct slist *n, *prev; - struct htable *ht = h->table; - struct type_pf_elem *data; - void *tmp; - int i = 0, j = 0; - u32 hash; - - if (h->elements >= h->maxelem) - return -IPSET_ERR_HASH_FULL; - - hash = JHASH2(value, h->initval, ht->htable_bits); - slist_for_each_prev(prev, n, &ht->htable[hash]) { - for (i = 0; i < h->array_size; i++) { - data = chash_data(n, i); - if (type_pf_data_isnull(data)) { - tmp = n; - goto found; - } - if (type_pf_data_equal(data, d)) - return -IPSET_ERR_EXIST; - } - j++; - } - if (j < h->chain_limit) { - tmp = kzalloc(h->array_size * sizeof(struct type_pf_elem) - + sizeof(struct slist), gfp_flags); - if (!tmp) - return -ENOMEM; - prev->next = (struct slist *) tmp; - data = chash_data(tmp, 0); - } else { - /* Rehashing */ - return -EAGAIN; - } -found: - type_pf_data_copy(data, d); -#ifdef IP_SET_HASH_WITH_NETS - 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) -{ - struct chash *h = set->data; - const struct type_pf_elem *d = value; - struct htable *ht = h->table; - struct slist *n, *prev; - int i; - struct type_pf_elem *data; - u32 hash = JHASH2(value, h->initval, ht->htable_bits); - - slist_for_each_prev(prev, n, &ht->htable[hash]) - for (i = 0; i < h->array_size; i++) { - data = chash_data(n, i); - if (type_pf_data_isnull(data)) - return -IPSET_ERR_EXIST; - if (type_pf_data_equal(data, d)) { - type_pf_chash_del_elem(h, prev, n, i); - return 0; - } - } - - return -IPSET_ERR_EXIST; -} - -#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, - gfp_t gfp_flags, u32 timeout) -{ - struct chash *h = set->data; - struct htable *ht = h->table; - struct slist *n; - const struct type_pf_elem *data; - int i, j = 0; - u32 hash; - u8 host_mask = SET_HOST_MASK(set->family); - -retry: - pr_debug("test by nets"); - for (; j < host_mask && h->nets[j].cidr; j++) { - type_pf_data_netmask(d, h->nets[j].cidr); - hash = JHASH2(d, h->initval, ht->htable_bits); - slist_for_each(n, &ht->htable[hash]) - for (i = 0; i < h->array_size; i++) { - data = chash_data(n, i); - if (type_pf_data_isnull(data)) { - j++; - goto retry; - } - if (type_pf_data_equal(data, d)) - return 1; - } - } - return 0; -} -#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) -{ - struct chash *h = set->data; - struct htable *ht = h->table; - struct type_pf_elem *d = value; - struct slist *n; - const struct type_pf_elem *data; - int i; - u32 hash; - -#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 - - hash = JHASH2(d, h->initval, ht->htable_bits); - slist_for_each(n, &ht->htable[hash]) - for (i = 0; i < h->array_size; i++) { - data = chash_data(n, i); - if (type_pf_data_isnull(data)) - return 0; - if (type_pf_data_equal(data, d)) - return 1; - } - 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) -{ - const struct chash *h = set->data; - struct nlattr *nested; - size_t memsize; - - read_lock_bh(&set->lock); - memsize = chash_memsize(h, with_timeout(h->timeout) - ? sizeof(struct type_pf_telem) - : sizeof(struct type_pf_elem), - set->family == AF_INET ? 32 : 128); - read_unlock_bh(&set->lock); - - nested = ipset_nest_start(skb, IPSET_ATTR_DATA); - if (!nested) - goto nla_put_failure; - NLA_PUT_NET32(skb, IPSET_ATTR_HASHSIZE, - htonl(jhash_size(h->table->htable_bits))); - NLA_PUT_NET32(skb, IPSET_ATTR_MAXELEM, htonl(h->maxelem)); -#ifdef IP_SET_HASH_WITH_NETMASK - if (h->netmask != HOST_MASK) - NLA_PUT_U8(skb, IPSET_ATTR_NETMASK, h->netmask); -#endif - NLA_PUT_NET32(skb, IPSET_ATTR_REFERENCES, - htonl(atomic_read(&set->ref) - 1)); - NLA_PUT_NET32(skb, IPSET_ATTR_MEMSIZE, htonl(memsize)); - if (with_timeout(h->timeout)) - NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT, htonl(h->timeout)); - ipset_nest_end(skb, nested); - - return 0; -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) -{ - const struct chash *h = set->data; - const struct htable *ht = h->table; - struct nlattr *atd, *nested; - struct slist *n; - const struct type_pf_elem *data; - u32 first = cb->args[2]; - /* We assume that one hash bucket fills into one page */ - void *incomplete; - int i; - - atd = ipset_nest_start(skb, IPSET_ATTR_ADT); - if (!atd) - return -EFAULT; - pr_debug("list hash set %s", set->name); - for (; cb->args[2] < jhash_size(ht->htable_bits); cb->args[2]++) { - incomplete = skb_tail_pointer(skb); - slist_for_each(n, &ht->htable[cb->args[2]]) { - for (i = 0; i < h->array_size; i++) { - data = chash_data(n, i); - if (type_pf_data_isnull(data)) - break; - pr_debug("list hash %lu slist %p i %u", - cb->args[2], n, i); - nested = ipset_nest_start(skb, IPSET_ATTR_DATA); - if (!nested) { - if (cb->args[2] == first) { - nla_nest_cancel(skb, atd); - return -EFAULT; - } else - goto nla_put_failure; - } - if (type_pf_data_list(skb, data)) - goto nla_put_failure; - ipset_nest_end(skb, nested); - } - } - } - ipset_nest_end(skb, atd); - /* Set listing finished */ - cb->args[2] = 0; - - return 0; - -nla_put_failure: - nlmsg_trim(skb, incomplete); - ipset_nest_end(skb, atd); - if (unlikely(first == cb->args[2])) { - pr_warn("Can't list set %s: one bucket does not fit into " - "a message. Please report it!\n", set->name); - cb->args[2] = 0; - } - return 0; -} - -static int -type_pf_kadt(struct ip_set *set, const struct sk_buff * skb, - enum ipset_adt adt, u8 pf, u8 dim, u8 flags); -static int -type_pf_uadt(struct ip_set *set, struct nlattr *head, int len, - enum ipset_adt adt, u32 *lineno, u32 flags); - -static const struct ip_set_type_variant type_pf_variant __read_mostly = { - .kadt = type_pf_kadt, - .uadt = type_pf_uadt, - .adt = { - [IPSET_ADD] = type_pf_chash_add, - [IPSET_DEL] = type_pf_chash_del, - [IPSET_TEST] = type_pf_chash_test, - }, - .destroy = type_pf_destroy, - .flush = type_pf_flush, - .head = type_pf_head, - .list = type_pf_list, - .resize = type_pf_resize, - .same_set = type_pf_same_set, -}; - -/* Flavour with timeout support */ - -#define chash_tdata(n, i) \ -(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) -{ - const struct type_pf_telem *tdata = - (const struct type_pf_telem *) data; - - return tdata->timeout; -} - -static inline bool -type_pf_data_expired(const struct type_pf_elem *data) -{ - const struct type_pf_telem *tdata = - (const struct type_pf_telem *) data; - - return ip_set_timeout_expired(tdata->timeout); -} - -static inline void -type_pf_data_swap_timeout(struct type_pf_elem *src, - struct type_pf_elem *dst) -{ - struct type_pf_telem *x = (struct type_pf_telem *) src; - struct type_pf_telem *y = (struct type_pf_telem *) dst; - - swap(x->timeout, y->timeout); -} - -static inline void -type_pf_data_timeout_set(struct type_pf_elem *data, u32 timeout) -{ - struct type_pf_telem *tdata = (struct type_pf_telem *) data; - - tdata->timeout = ip_set_timeout_set(timeout); -} - -static int -type_pf_chash_treadd(struct chash *h, struct htable *ht, - const struct type_pf_elem *value, - gfp_t gfp_flags, u32 timeout) -{ - struct slist *n, *prev; - struct type_pf_elem *data; - void *tmp; - int i = 0, j = 0; - u32 hash = JHASH2(value, h->initval, ht->htable_bits); - - slist_for_each_prev(prev, n, &ht->htable[hash]) { - for (i = 0; i < h->array_size; i++) { - data = chash_tdata(n, i); - if (type_pf_data_isnull(data)) { - tmp = n; - goto found; - } - } - j++; - } - if (j < h->chain_limit) { - tmp = kzalloc(h->array_size * sizeof(struct type_pf_telem) - + sizeof(struct slist), gfp_flags); - if (!tmp) - return -ENOMEM; - prev->next = (struct slist *) tmp; - data = chash_tdata(tmp, 0); - } else { - /* Trigger rehashing */ - return -EAGAIN; - } -found: - type_pf_data_copy(data, value); - type_pf_data_timeout_set(data, timeout); - return 0; -} - -static void -type_pf_chash_del_telem(struct chash *h, struct slist *prev, - struct slist *n, int i) -{ - struct type_pf_elem *d, *data = chash_tdata(n, i); - struct slist *tmp; - int j; /* Index in array */ - - pr_debug("del %u", i); - if (n->next != NULL) { - for (prev = n, tmp = n->next; - tmp->next != NULL; - prev = tmp, tmp = tmp->next) - /* Find last array */; - j = 0; - } else { - /* Already at last array */ - tmp = n; - j = i; - } - /* Find last non-empty element */ - for (; j < h->array_size - 1; j++) - if (type_pf_data_isnull(chash_tdata(tmp, j + 1))) - break; - - d = chash_tdata(tmp, j); - if (!(tmp == n && i == j)) { - type_pf_data_swap(data, d); - type_pf_data_swap_timeout(data, d); - } -#ifdef IP_SET_HASH_WITH_NETS - del_cidr(h, data->cidr, HOST_MASK); -#endif - if (j == 0) { - prev->next = NULL; - kfree(tmp); - } else - type_pf_data_zero_out(d); - - h->elements--; -} - -/* Delete expired elements from the hashtable */ -static void -type_pf_chash_expire(struct chash *h) -{ - struct htable *ht = h->table; - struct slist *n, *prev; - struct type_pf_elem *data; - u32 i; - int j; - - for (i = 0; i < jhash_size(ht->htable_bits); i++) - slist_for_each_prev(prev, n, &ht->htable[i]) - for (j = 0; j < h->array_size; j++) { - data = chash_tdata(n, j); - if (type_pf_data_isnull(data)) - break; - if (type_pf_data_expired(data)) { - pr_debug("expire %u/%u", i, j); - type_pf_chash_del_telem(h, prev, n, j); - } - } -} - -static int -type_pf_tresize(struct ip_set *set, gfp_t gfp_flags, bool retried) -{ - struct chash *h = set->data; - struct htable *ht, *orig = h->table; - u8 htable_bits = orig->htable_bits; - struct slist *n; - const struct type_pf_elem *data; - u32 i, j; - int ret; - - /* Try to cleanup once */ - if (!retried) { - i = h->elements; - write_lock_bh(&set->lock); - type_pf_chash_expire(set->data); - write_unlock_bh(&set->lock); - if (h->elements < i) - return 0; - } - -retry: - ret = i = 0; - htable_bits++; - if (!htable_bits) - /* In case we have plenty of memory :-) */ - return -IPSET_ERR_HASH_FULL; - ht = ip_set_alloc(sizeof(*ht) - + jhash_size(htable_bits) * sizeof(struct slist), - GFP_KERNEL); - if (!ht) - return -ENOMEM; - ht->htable_bits = htable_bits; - - read_lock_bh(&set->lock); -next_slot: - for (; i < jhash_size(orig->htable_bits); i++) { - slist_for_each(n, &orig->htable[i]) { - for (j = 0; j < h->array_size; j++) { - data = chash_tdata(n, j); - if (type_pf_data_isnull(data)) { - i++; - goto next_slot; - } - ret = type_pf_chash_treadd(h, ht, - data, gfp_flags, - type_pf_data_timeout(data)); - if (ret < 0) { - read_unlock_bh(&set->lock); - chash_destroy(ht); - if (ret == -EAGAIN) - goto retry; - return ret; - } - } - } - } - - h->table = ht; - read_unlock_bh(&set->lock); - - /* Give time to other users of the set */ - synchronize_net(); - - chash_destroy(orig); - - return 0; -} - -static int -type_pf_chash_tadd(struct ip_set *set, void *value, - gfp_t gfp_flags, u32 timeout) -{ - struct chash *h = set->data; - const struct type_pf_elem *d = value; - struct slist *n, *prev; - struct htable *ht = h->table; - struct type_pf_elem *data; - void *tmp; - int i = 0, j = 0; - u32 hash; - - if (h->elements >= h->maxelem) - /* FIXME: when set is full, we slow down here */ - type_pf_chash_expire(h); - if (h->elements >= h->maxelem) - return -IPSET_ERR_HASH_FULL; - - hash = JHASH2(d, h->initval, ht->htable_bits); - slist_for_each_prev(prev, n, &ht->htable[hash]) { - for (i = 0; i < h->array_size; i++) { - data = chash_tdata(n, i); - if (type_pf_data_isnull(data) - || type_pf_data_expired(data)) { - tmp = n; - goto found; - } - if (type_pf_data_equal(data, d)) - return -IPSET_ERR_EXIST; - } - j++; - } - if (j < h->chain_limit) { - tmp = kzalloc(h->array_size * sizeof(struct type_pf_telem) - + sizeof(struct slist), gfp_flags); - if (!tmp) - return -ENOMEM; - prev->next = (struct slist *) tmp; - data = chash_tdata(tmp, 0); - } else { - /* Rehashing */ - return -EAGAIN; - } -found: - if (type_pf_data_isnull(data)) - h->elements++; -#ifdef IP_SET_HASH_WITH_NETS - 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; -} - -static int -type_pf_chash_tdel(struct ip_set *set, void *value, - gfp_t gfp_flags, u32 timeout) -{ - struct chash *h = set->data; - struct htable *ht = h->table; - const struct type_pf_elem *d = value; - struct slist *n, *prev; - int i, ret = 0; - struct type_pf_elem *data; - u32 hash = JHASH2(value, h->initval, ht->htable_bits); - - slist_for_each_prev(prev, n, &ht->htable[hash]) - for (i = 0; i < h->array_size; i++) { - data = chash_tdata(n, i); - if (type_pf_data_isnull(data)) - return -IPSET_ERR_EXIST; - if (type_pf_data_equal(data, d)) { - if (type_pf_data_expired(data)) - ret = -IPSET_ERR_EXIST; - type_pf_chash_del_telem(h, prev, n, i); - return ret; - } - } - - return -IPSET_ERR_EXIST; -} - -#ifdef IP_SET_HASH_WITH_NETS -static inline int -type_pf_chash_ttest_cidrs(struct ip_set *set, - struct type_pf_elem *d, - gfp_t gfp_flags, u32 timeout) -{ - struct chash *h = set->data; - struct htable *ht = h->table; - struct type_pf_elem *data; - struct slist *n; - int i, j = 0; - u32 hash; - u8 host_mask = SET_HOST_MASK(set->family); - -retry: - for (; j < host_mask && h->nets[j].cidr; j++) { - type_pf_data_netmask(d, h->nets[j].cidr); - hash = JHASH2(d, h->initval, ht->htable_bits); - slist_for_each(n, &ht->htable[hash]) - for (i = 0; i < h->array_size; i++) { - data = chash_tdata(n, i); - if (type_pf_data_isnull(data)) { - j++; - goto retry; - } - if (type_pf_data_equal(data, d)) - return !type_pf_data_expired(data); - } - } - return 0; -} -#endif - -static inline int -type_pf_chash_ttest(struct ip_set *set, void *value, - gfp_t gfp_flags, u32 timeout) -{ - struct chash *h = set->data; - struct htable *ht = h->table; - struct type_pf_elem *data, *d = value; - struct slist *n; - int i; - u32 hash; - -#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 - hash = JHASH2(d, h->initval, ht->htable_bits); - slist_for_each(n, &ht->htable[hash]) - for (i = 0; i < h->array_size; i++) { - data = chash_tdata(n, i); - if (type_pf_data_isnull(data)) - return 0; - if (type_pf_data_equal(data, d)) - return !type_pf_data_expired(data); - } - return 0; -} - -static int -type_pf_tlist(struct ip_set *set, - struct sk_buff *skb, struct netlink_callback *cb) -{ - const struct chash *h = set->data; - const struct htable *ht = h->table; - struct nlattr *atd, *nested; - struct slist *n; - const struct type_pf_elem *data; - u32 first = cb->args[2]; - /* We assume that one hash bucket fills into one page */ - void *incomplete; - int i; - - atd = ipset_nest_start(skb, IPSET_ATTR_ADT); - if (!atd) - return -EFAULT; - for (; cb->args[2] < jhash_size(ht->htable_bits); cb->args[2]++) { - incomplete = skb_tail_pointer(skb); - slist_for_each(n, &ht->htable[cb->args[2]]) { - for (i = 0; i < h->array_size; i++) { - data = chash_tdata(n, i); - pr_debug("list %p %u", n, i); - if (type_pf_data_isnull(data)) - break; - if (type_pf_data_expired(data)) - continue; - pr_debug("do list %p %u", n, i); - nested = ipset_nest_start(skb, IPSET_ATTR_DATA); - if (!nested) { - if (cb->args[2] == first) { - nla_nest_cancel(skb, atd); - return -EFAULT; - } else - goto nla_put_failure; - } - if (type_pf_data_tlist(skb, data)) - goto nla_put_failure; - ipset_nest_end(skb, nested); - } - } - } - ipset_nest_end(skb, atd); - /* Set listing finished */ - cb->args[2] = 0; - - return 0; - -nla_put_failure: - nlmsg_trim(skb, incomplete); - ipset_nest_end(skb, atd); - if (unlikely(first == cb->args[2])) { - pr_warn("Can't list set %s: one bucket does not fit into " - "a message. Please report it!\n", set->name); - cb->args[2] = 0; - } - return 0; -} - -static const struct ip_set_type_variant type_pf_tvariant __read_mostly = { - .kadt = type_pf_kadt, - .uadt = type_pf_uadt, - .adt = { - [IPSET_ADD] = type_pf_chash_tadd, - [IPSET_DEL] = type_pf_chash_tdel, - [IPSET_TEST] = type_pf_chash_ttest, - }, - .destroy = type_pf_destroy, - .flush = type_pf_flush, - .head = type_pf_head, - .list = type_pf_tlist, - .resize = type_pf_tresize, - .same_set = type_pf_same_set, -}; - -static void -type_pf_gc(unsigned long ul_set) -{ - struct ip_set *set = (struct ip_set *) ul_set; - struct chash *h = set->data; - - pr_debug("called"); - write_lock_bh(&set->lock); - type_pf_chash_expire(h); - write_unlock_bh(&set->lock); - - h->gc.expires = jiffies + IPSET_GC_PERIOD(h->timeout) * HZ; - add_timer(&h->gc); -} - -static inline void -type_pf_gc_init(struct ip_set *set) -{ - struct chash *h = set->data; - - init_timer(&h->gc); - h->gc.data = (unsigned long) 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)); -} - -#undef type_pf_data_equal -#undef type_pf_data_isnull -#undef type_pf_data_copy -#undef type_pf_data_swap -#undef type_pf_data_zero_out -#undef type_pf_data_list -#undef type_pf_data_tlist - -#undef type_pf_elem -#undef type_pf_telem -#undef type_pf_data_timeout -#undef type_pf_data_expired -#undef type_pf_data_swap_timeout -#undef type_pf_data_netmask -#undef type_pf_data_timeout_set - -#undef type_pf_chash_readd -#undef type_pf_chash_del_elem -#undef type_pf_chash_add -#undef type_pf_chash_del -#undef type_pf_chash_test_cidrs -#undef type_pf_chash_test - -#undef type_pf_chash_treadd -#undef type_pf_chash_del_telem -#undef type_pf_chash_expire -#undef type_pf_chash_tadd -#undef type_pf_chash_tdel -#undef type_pf_chash_ttest_cidrs -#undef type_pf_chash_ttest - -#undef type_pf_resize -#undef type_pf_tresize -#undef type_pf_flush -#undef type_pf_destroy -#undef type_pf_head -#undef type_pf_list -#undef type_pf_tlist -#undef type_pf_same_set -#undef type_pf_kadt -#undef type_pf_uadt -#undef type_pf_gc -#undef type_pf_gc_init -#undef type_pf_variant -#undef type_pf_tvariant diff --git a/kernel/include/linux/netfilter/ip_set_getport.h b/kernel/include/linux/netfilter/ip_set_getport.h deleted file mode 100644 index 1597fa9..0000000 --- a/kernel/include/linux/netfilter/ip_set_getport.h +++ /dev/null @@ -1,126 +0,0 @@ -#ifndef _IP_SET_GETPORT_H -#define _IP_SET_GETPORT_H - -#ifdef __KERNEL__ -#include -#include -#include -#include - -#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) -{ - switch (protocol) { - case IPPROTO_TCP: { - struct tcphdr _tcph; - const struct tcphdr *th; - - th = skb_header_pointer(skb, protooff, sizeof(_tcph), &_tcph); - if (th == NULL) - /* No choice either */ - return false; - - *port = src ? th->source : th->dest; - break; - } - case IPPROTO_UDP: { - struct udphdr _udph; - const struct udphdr *uh; - - uh = skb_header_pointer(skb, protooff, sizeof(_udph), &_udph); - if (uh == NULL) - /* No choice either */ - return false; - - *port = src ? uh->source : uh->dest; - break; - } - 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; - } - *proto = protocol; - - return true; -} - -static inline bool -get_ip4_port(const struct sk_buff *skb, bool src, u16 *port, u8 *proto) -{ - const struct iphdr *iph = ip_hdr(skb); - unsigned int protooff = ip_hdrlen(skb); - int protocol = iph->protocol; - - /* See comments at tcp_match in ip_tables.c */ - if (ntohs(iph->frag_off) & IP_OFFSET) - return false; - - return get_port(skb, protocol, protooff, src, port, proto); -} - -static inline bool -get_ip6_port(const struct sk_buff *skb, bool src, u16 *port, u8 *proto) -{ - unsigned int protooff = 0; - int protocol; - unsigned short fragoff; - - protocol = ipv6_find_hdr(skb, &protooff, -1, &fragoff); - if (protocol < 0 || fragoff) - 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) -{ - 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__ */ - -#endif /*_IP_SET_GETPORT_H*/ diff --git a/kernel/include/linux/netfilter/ip_set_hash.h b/kernel/include/linux/netfilter/ip_set_hash.h deleted file mode 100644 index b86f15c..0000000 --- a/kernel/include/linux/netfilter/ip_set_hash.h +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef __IP_SET_HASH_H -#define __IP_SET_HASH_H - -/* 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, -}; - -#ifdef __KERNEL__ - -#define IPSET_DEFAULT_HASHSIZE 1024 -#define IPSET_MIMINAL_HASHSIZE 64 -#define IPSET_DEFAULT_MAXELEM 65536 -#define IPSET_DEFAULT_PROBES 4 -#define IPSET_DEFAULT_RESIZE 100 - -#endif /* __KERNEL__ */ - -#endif /* __IP_SET_HASH_H */ diff --git a/kernel/include/linux/netfilter/ip_set_jhash.h b/kernel/include/linux/netfilter/ip_set_jhash.h deleted file mode 100644 index d5e0d6d..0000000 --- a/kernel/include/linux/netfilter/ip_set_jhash.h +++ /dev/null @@ -1,121 +0,0 @@ -#ifndef _LINUX_JHASH_H -#define _LINUX_JHASH_H -/* jhash.c: Jenkins hash support. - * - * Copyright (C) 2006. Bob Jenkins (bob_jenkins@burtleburtle.net) - * - * http://burtleburtle.net/bob/hash/ - * - * These are the credits from Bob's sources: - * - * lookup3.c, by Bob Jenkins, May 2006, Public Domain. - * - * These are functions for producing 32-bit hashes for hash table lookup. - * hashword(), hashlittle(), hashlittle2(), hashbig(), mix(), and final() - * are externally useful functions. Routines to test the hash are included - * if SELF_TEST is defined. You can use this free for any purpose. It's in - * the public domain. It has no warranty. - * - * Copyright (C) 2009-2010 Jozsef Kadlecsik (kadlec@blackhole.kfki.hu) - * - * I've modified Bob's hash to be useful in the Linux kernel, and - * any bugs present are my fault. The generic jhash is left out intentionally. - * Jozsef - */ -#ifdef __KERNEL__ -#include - -/* Best hash sizes are of power of two */ -#define jhash_size(n) ((u32)1<<(n)) -/* Mask the hash value, i.e (value & jhash_mask(n)) instead of (value % n) */ -#define jhash_mask(n) (jhash_size(n)-1) - -/* __jhash_rot - rotate 32 bit */ -#define __jhash_rot(x,k) (((x)<<(k)) | ((x)>>(32-(k)))) - -/* __jhash_mix -- mix 3 32-bit values reversibly. */ -#define __jhash_mix(a,b,c) \ -{ \ - a -= c; a ^= __jhash_rot(c, 4); c += b; \ - b -= a; b ^= __jhash_rot(a, 6); a += c; \ - c -= b; c ^= __jhash_rot(b, 8); b += a; \ - a -= c; a ^= __jhash_rot(c,16); c += b; \ - b -= a; b ^= __jhash_rot(a,19); a += c; \ - c -= b; c ^= __jhash_rot(b, 4); b += a; \ -} - -/* __jhash_final - final mixing of 3 32-bit values (a,b,c) into c */ -#define __jhash_final(a,b,c) \ -{ \ - c ^= b; c -= __jhash_rot(b,14); \ - a ^= c; a -= __jhash_rot(c,11); \ - b ^= a; b -= __jhash_rot(a,25); \ - c ^= b; c -= __jhash_rot(b,16); \ - a ^= c; a -= __jhash_rot(c,4); \ - b ^= a; b -= __jhash_rot(a,14); \ - c ^= b; c -= __jhash_rot(b,24); \ -} - -#define JHASH_INITVAL 0xdeadbeef - -/* jhash2 - hash an array of u32's - * @k: the key which must be an array of u32's - * @length: the number of u32's in the key - * @initval: the previous hash, or an arbitray value - * - * Returns the hash value of the key. - */ -static inline u32 jhash2(const u32 *k, u32 length, u32 initval) -{ - u32 a, b, c; - - /* Set up the internal state */ - a = b = c = JHASH_INITVAL + (length<<2) + initval; - - /* Handle most of the key */ - while (length > 3) { - a += k[0]; - b += k[1]; - c += k[2]; - __jhash_mix(a,b,c); - length -= 3; - k += 3; - } - - /* Handle the last 3 u32's: all the case statements fall through */ - switch(length) { - case 3: c += k[2]; - case 2: b += k[1]; - case 1: a += k[0]; - __jhash_final(a,b,c); - case 0: /* Nothing left to add */ - break; - } - - return c; -} - -/* jhash_3words - hash exactly 3, 2 or 1 word(s) */ -static inline u32 jhash_3words(u32 a, u32 b, u32 c, u32 initval) -{ - a += JHASH_INITVAL; - b += JHASH_INITVAL; - c += initval; - - __jhash_final(a,b,c); - - return c; -} -static inline u32 jhash_2words(u32 a, u32 b, u32 initval) -{ - return jhash_3words(a, b, 0, initval); -} - -static inline u32 jhash_1word(u32 a, u32 initval) -{ - return jhash_3words(a, 0, 0, initval); -} - -#endif /* __KERNEL__ */ - -#endif /* _LINUX_JHASH_H */ diff --git a/kernel/include/linux/netfilter/ip_set_kernel.h b/kernel/include/linux/netfilter/ip_set_kernel.h deleted file mode 100644 index d770589..0000000 --- a/kernel/include/linux/netfilter/ip_set_kernel.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef _IP_SET_KERNEL_H -#define _IP_SET_KERNEL_H - -#ifdef __KERNEL__ - -#ifdef CONFIG_DEBUG_KERNEL -/* Complete debug messages */ -#define pr_fmt(fmt) "%s %s[%i]: " fmt "\n", __FILE__, __func__, __LINE__ -#endif - -#include - -#endif /* __KERNEL__ */ - -#endif /*_IP_SET_H */ diff --git a/kernel/include/linux/netfilter/ip_set_list.h b/kernel/include/linux/netfilter/ip_set_list.h deleted file mode 100644 index 40a63f3..0000000 --- a/kernel/include/linux/netfilter/ip_set_list.h +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef __IP_SET_LIST_H -#define __IP_SET_LIST_H - -/* 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, -}; - -#ifdef __KERNEL__ - -#define IP_SET_LIST_DEFAULT_SIZE 8 -#define IP_SET_LIST_MIN_SIZE 4 - -#endif /* __KERNEL__ */ - -#endif /* __IP_SET_LIST_H */ diff --git a/kernel/include/linux/netfilter/ip_set_slist.h b/kernel/include/linux/netfilter/ip_set_slist.h deleted file mode 100644 index e472e43..0000000 --- a/kernel/include/linux/netfilter/ip_set_slist.h +++ /dev/null @@ -1,89 +0,0 @@ -#ifndef _IP_SET_SLIST_H -#define _IP_SET_SLIST_H - -#include -#include -#include - -/* - * Single linked lists with a single pointer. - * Mostly useful for hash tables where the two pointer list head - * and list node is too wasteful. - */ - -struct slist { - struct slist *next; -}; - -#define SLIST(name) struct slist name = { .next = NULL } -#define INIT_SLIST(ptr) ((ptr)->next = NULL) - -#define slist_entry(ptr, type, member) container_of(ptr, type, member) - -#define slist_for_each(pos, head) \ - for (pos = (head)->next; pos && ({ prefetch(pos->next); 1; }); \ - pos = pos->next) - -#define slist_for_each_prev(prev, pos, head) \ - for (prev = head, pos = (head)->next; \ - pos && ({ prefetch(pos->next); 1; }); \ - prev = pos, pos = pos->next) - -#define slist_for_each_safe(pos, n, head) \ - for (pos = (head)->next; pos && ({ n = pos->next; 1; }); \ - pos = n) - -/** - * slist_for_each_entry - iterate over list of given type - * @tpos: the type * to use as a loop cursor. - * @pos: the &struct slist to use as a loop cursor. - * @head: the head for your list. - * @member: the name of the slist within the struct. - */ -#define slist_for_each_entry(tpos, pos, head, member) \ - for (pos = (head)->next; \ - pos && ({ prefetch(pos->next); 1; }) && \ - ({ tpos = slist_entry(pos, typeof(*tpos), member); 1; });\ - pos = pos->next) - -/** - * 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. - */ -#define slist_for_each_entry_continue(tpos, pos, member) \ - for (pos = (pos)->next; \ - pos && ({ prefetch(pos->next); 1; }) && \ - ({ tpos = slist_entry(pos, typeof(*tpos), member); 1; });\ - pos = pos->next) - -/** - * 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. - */ -#define slist_for_each_entry_from(tpos, pos, member) \ - for (; pos && ({ prefetch(pos->next); 1; }) && \ - ({ tpos = slist_entry(pos, typeof(*tpos), member); 1; });\ - pos = pos->next) - -/** - * slist_for_each_entry_safe - iterate over list of given type safe against - * removal of list entry - * @tpos: the type * to use as a loop cursor. - * @pos: the &struct slist to use as a loop cursor. - * @n: another &struct slist to use as temporary storage - * @head: the head for your list. - * @member: the name of the slist within the struct. - */ -#define slist_for_each_entry_safe(tpos, pos, n, head, member) \ - for (pos = (head)->next; \ - pos && ({ n = pos->next; 1; }) && \ - ({ tpos = slist_entry(pos, typeof(*tpos), member); 1; });\ - pos = n) - -#endif /* _IP_SET_SLIST_H */ diff --git a/kernel/include/linux/netfilter/ip_set_timeout.h b/kernel/include/linux/netfilter/ip_set_timeout.h deleted file mode 100644 index 519d84f..0000000 --- a/kernel/include/linux/netfilter/ip_set_timeout.h +++ /dev/null @@ -1,127 +0,0 @@ -#ifndef _IP_SET_TIMEOUT_H -#define _IP_SET_TIMEOUT_H - -/* Copyright (C) 2003-2010 Jozsef Kadlecsik - * - * 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__ - -/* How often should the gc be run by default */ -#define IPSET_GC_TIME (3 * 60) - -/* Timeout period depending on the timeout value of the given set */ -#define IPSET_GC_PERIOD(timeout) \ - ((timeout/3) ? min_t(u32, (timeout)/3, IPSET_GC_TIME) : 1) - -/* 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) - -static inline unsigned int -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 */ -#define IPSET_ELEM_PERMANENT (UINT_MAX/2) - -static inline bool -ip_set_timeout_test(unsigned long timeout) -{ - return timeout != IPSET_ELEM_UNSET - && (timeout == IPSET_ELEM_PERMANENT - || time_after(timeout, jiffies)); -} - -static inline bool -ip_set_timeout_expired(unsigned long timeout) -{ - return timeout != IPSET_ELEM_UNSET - && timeout != IPSET_ELEM_PERMANENT - && time_before(timeout, jiffies); -} - -static inline unsigned long -ip_set_timeout_set(u32 timeout) -{ - unsigned long t; - - if (!timeout) - return IPSET_ELEM_PERMANENT; - - t = timeout * HZ + jiffies; - if (t == IPSET_ELEM_UNSET || t == IPSET_ELEM_PERMANENT) - /* Bingo! */ - t++; - - return t; -} - -static inline u32 -ip_set_timeout_get(unsigned long timeout) -{ - return timeout == IPSET_ELEM_PERMANENT ? 0 : (timeout - jiffies)/HZ; -} - -#else - -/* Hash specific timeout constants and macros for the entries */ - -/* Hash entry is set with no timeout value */ -#define IPSET_ELEM_PERMANENT 0 - -static inline bool -ip_set_timeout_test(unsigned long timeout) -{ - return timeout == IPSET_ELEM_PERMANENT - || time_after(timeout, jiffies); -} - -static inline bool -ip_set_timeout_expired(unsigned long timeout) -{ - return timeout != IPSET_ELEM_PERMANENT - && time_before(timeout, jiffies); -} - -static inline unsigned long -ip_set_timeout_set(u32 timeout) -{ - unsigned long t; - - if (!timeout) - return IPSET_ELEM_PERMANENT; - - t = timeout * HZ + jiffies; - if (t == IPSET_ELEM_PERMANENT) - /* Bingo! :-) */ - t++; - - return t; -} - -static inline u32 -ip_set_timeout_get(unsigned long timeout) -{ - return timeout == IPSET_ELEM_PERMANENT ? 0 : (timeout - jiffies)/HZ; -} -#endif /* ! IP_SET_BITMAP_TIMEOUT */ - -#endif /* __KERNEL__ */ - -#endif /* _IP_SET_TIMEOUT_H */ diff --git a/kernel/include/linux/netfilter/ipset/ip_set.h b/kernel/include/linux/netfilter/ipset/ip_set.h new file mode 100644 index 0000000..1e18b14 --- /dev/null +++ b/kernel/include/linux/netfilter/ipset/ip_set.h @@ -0,0 +1,526 @@ +#ifndef _IP_SET_H +#define _IP_SET_H + +/* Copyright (C) 2000-2002 Joakim Axelsson + * Patrick Schaaf + * Martin Josefsson + * Copyright (C) 2003-2010 Jozsef Kadlecsik + * + * 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. + */ + +/* The protocol version */ +#define IPSET_PROTOCOL 5 + +/* The max length of strings including NUL: set and type identifiers */ +#define IPSET_MAXNAMELEN 32 + +/* Message types and commands */ +enum ipset_cmd { + IPSET_CMD_NONE, + IPSET_CMD_PROTOCOL, /* 1: Return protocol version */ + IPSET_CMD_CREATE, /* 2: Create a new (empty) set */ + IPSET_CMD_DESTROY, /* 3: Destroy a (empty) set */ + IPSET_CMD_FLUSH, /* 4: Remove all elements from a set */ + IPSET_CMD_RENAME, /* 5: Rename a set */ + IPSET_CMD_SWAP, /* 6: Swap two sets */ + IPSET_CMD_LIST, /* 7: List sets */ + IPSET_CMD_SAVE, /* 8: Save sets */ + IPSET_CMD_ADD, /* 9: Add an element to a set */ + IPSET_CMD_DEL, /* 10: Delete an element from a set */ + IPSET_CMD_TEST, /* 11: Test an element in a set */ + IPSET_CMD_HEADER, /* 12: Get set header data only */ + IPSET_CMD_TYPE, /* 13: Get set type */ + IPSET_MSG_MAX, /* Netlink message commands */ + + /* Commands in userspace: */ + IPSET_CMD_RESTORE = IPSET_MSG_MAX, /* 14: Enter restore mode */ + IPSET_CMD_HELP, /* 15: Get help */ + IPSET_CMD_VERSION, /* 16: Get program version */ + IPSET_CMD_QUIT, /* 17: Quit from interactive mode */ + + IPSET_CMD_MAX, + + IPSET_CMD_COMMIT = IPSET_CMD_MAX, /* 18: Commit buffered commands */ +}; + +/* Attributes at command level */ +enum { + IPSET_ATTR_UNSPEC, + 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, /* Setname at rename/swap */ + IPSET_ATTR_REVISION, /* 4: Settype revision */ + IPSET_ATTR_FAMILY, /* 5: Settype family */ + IPSET_ATTR_FLAGS, /* 6: Flags at command level */ + IPSET_ATTR_DATA, /* 7: Nested attributes */ + IPSET_ATTR_ADT, /* 8: Multiple data containers */ + IPSET_ATTR_LINENO, /* 9: Restore lineno */ + IPSET_ATTR_PROTOCOL_MIN, /* 10: Minimal supported version number */ + IPSET_ATTR_REVISION_MIN = IPSET_ATTR_PROTOCOL_MIN, /* type rev min */ + __IPSET_ATTR_CMD_MAX, +}; +#define IPSET_ATTR_CMD_MAX (__IPSET_ATTR_CMD_MAX - 1) + +/* CADT specific attributes */ +enum { + IPSET_ATTR_IP = IPSET_ATTR_UNSPEC + 1, + IPSET_ATTR_IP_FROM = IPSET_ATTR_IP, + IPSET_ATTR_IP_TO, /* 2 */ + IPSET_ATTR_CIDR, /* 3 */ + IPSET_ATTR_PORT, /* 4 */ + IPSET_ATTR_PORT_FROM = IPSET_ATTR_PORT, + IPSET_ATTR_PORT_TO, /* 5 */ + IPSET_ATTR_TIMEOUT, /* 6 */ + IPSET_ATTR_PROTO, /* 7 */ + IPSET_ATTR_CADT_FLAGS, /* 8 */ + IPSET_ATTR_CADT_LINENO = IPSET_ATTR_LINENO, /* 9 */ + /* Reserve empty slots */ + IPSET_ATTR_CADT_MAX = 16, + /* Create-only specific attributes */ + IPSET_ATTR_GC, + IPSET_ATTR_HASHSIZE, + IPSET_ATTR_MAXELEM, + IPSET_ATTR_NETMASK, + IPSET_ATTR_PROBES, + IPSET_ATTR_RESIZE, + IPSET_ATTR_SIZE, + /* Kernel-only */ + IPSET_ATTR_ELEMENTS, + IPSET_ATTR_REFERENCES, + IPSET_ATTR_MEMSIZE, + + __IPSET_ATTR_CREATE_MAX, +}; +#define IPSET_ATTR_CREATE_MAX (__IPSET_ATTR_CREATE_MAX - 1) + +/* ADT specific attributes */ +enum { + IPSET_ATTR_ETHER = IPSET_ATTR_CADT_MAX + 1, + IPSET_ATTR_NAME, + IPSET_ATTR_NAMEREF, + IPSET_ATTR_IP2, + IPSET_ATTR_CIDR2, + __IPSET_ATTR_ADT_MAX, +}; +#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, + IPSET_ERR_PROTOCOL, + IPSET_ERR_FIND_TYPE, + IPSET_ERR_MAX_SETS, + IPSET_ERR_BUSY, + IPSET_ERR_EXIST_SETNAME2, + IPSET_ERR_TYPE_MISMATCH, + IPSET_ERR_EXIST, + IPSET_ERR_INVALID_CIDR, + IPSET_ERR_INVALID_NETMASK, + 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), +}; + +/* Commands with settype-specific attributes */ +enum ipset_adt { + IPSET_ADD, + IPSET_DEL, + IPSET_TEST, + IPSET_ADT_MAX, + IPSET_CREATE = IPSET_ADT_MAX, + IPSET_CADT_MAX, +}; + +#ifdef __KERNEL__ +#include +#include +#include +#include +#include +#include + +/* Sets are identified by an index in kernel space. Tweak with ip_set_id_t + * and IPSET_INVALID_ID if you want to increase the max number of sets. + */ +typedef u16 ip_set_id_t; + +#define IPSET_INVALID_ID 65535 + +enum ip_set_dim { + IPSET_DIM_ZERO = 0, + IPSET_DIM_ONE, + IPSET_DIM_TWO, + IPSET_DIM_THREE, + /* Max dimension in elements. + * If changed, new revision of iptables match/target is required. + */ + IPSET_DIM_MAX = 6, +}; + +/* Option flags for kernel operations */ +enum ip_set_kopt { + IPSET_INV_MATCH = (1 << IPSET_DIM_ZERO), + IPSET_DIM_ONE_SRC = (1 << IPSET_DIM_ONE), + IPSET_DIM_TWO_SRC = (1 << IPSET_DIM_TWO), + IPSET_DIM_THREE_SRC = (1 << IPSET_DIM_THREE), +}; + +/* Set features */ +enum ip_set_feature { + IPSET_TYPE_IP_FLAG = 0, + IPSET_TYPE_IP = (1 << IPSET_TYPE_IP_FLAG), + IPSET_TYPE_PORT_FLAG = 1, + IPSET_TYPE_PORT = (1 << IPSET_TYPE_PORT_FLAG), + IPSET_TYPE_MAC_FLAG = 2, + IPSET_TYPE_MAC = (1 << IPSET_TYPE_MAC_FLAG), + IPSET_TYPE_IP2_FLAG = 3, + IPSET_TYPE_IP2 = (1 << IPSET_TYPE_IP2_FLAG), + IPSET_TYPE_NAME_FLAG = 4, + IPSET_TYPE_NAME = (1 << IPSET_TYPE_NAME_FLAG), + /* 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), +}; + +struct ip_set; + +typedef int (*ipset_adtfn)(struct ip_set *set, void *value, + gfp_t gfp_flags, u32 timeout); + +/* Set type, variant-specific part */ +struct ip_set_type_variant { + /* Kernelspace: test/add/del entries */ + int (*kadt)(struct ip_set *set, const struct sk_buff * skb, + enum ipset_adt adt, u8 pf, u8 dim, u8 flags); + + /* Userspace: test/add/del entries */ + int (*uadt)(struct ip_set *set, struct nlattr *head, int len, + enum ipset_adt adt, u32 *lineno, u32 flags); + + /* Low level add/del/test functions */ + ipset_adtfn adt[IPSET_ADT_MAX]; + + /* When adding entries and set is full, try to resize the set */ + int (*resize)(struct ip_set *set, gfp_t gfp_flags, bool retried); + /* Destroy the set */ + void (*destroy)(struct ip_set *set); + /* Flush the elements */ + void (*flush)(struct ip_set *set); + /* Expire entries before listing */ + void (*expire)(struct ip_set *set); + /* List set header data */ + int (*head)(struct ip_set *set, struct sk_buff *skb); + /* List elements */ + int (*list)(struct ip_set *set, struct sk_buff *skb, + struct netlink_callback *cb); + + /* Return true if "b" set is the same as "a" + * according to the create set parameters */ + bool (*same_set)(const struct ip_set *a, const struct ip_set *b); +}; + +/* The core set type structure */ +struct ip_set_type { + struct list_head list; + + /* Typename */ + char name[IPSET_MAXNAMELEN]; + /* Protocol version */ + u8 protocol; + /* Set features to control swapping */ + u8 features; + /* Set type dimension */ + u8 dimension; + /* Supported family: may be AF_UNSPEC for both AF_INET/AF_INET6 */ + u8 family; + /* Type revision */ + u8 revision; + + /* Create set */ + int (*create)(struct ip_set *set, + struct nlattr *head, int len, u32 flags); + + /* Set this to THIS_MODULE if you are a module, otherwise NULL */ + struct module *me; +}; + +extern int ip_set_type_register(struct ip_set_type *set_type); +extern void ip_set_type_unregister(struct ip_set_type *set_type); + +/* A generic IP set */ +struct ip_set { + /* The name of the set */ + char name[IPSET_MAXNAMELEN]; + /* Lock protecting the set data */ + rwlock_t lock; + /* References to the set */ + atomic_t ref; + /* The core set type */ + const struct ip_set_type *type; + /* The type variant doing the real job */ + const struct ip_set_type_variant *variant; + /* The actual INET family of the set */ + u8 family; + /* The type specific data */ + void *data; +}; + +/* register and unregister set references */ +extern ip_set_id_t ip_set_get_byname(const char *name, struct ip_set **set); +extern void ip_set_put_byindex(ip_set_id_t index); +extern const char * ip_set_name_byindex(ip_set_id_t index); +extern ip_set_id_t ip_set_nfnl_get(const char *name); +extern ip_set_id_t ip_set_nfnl_get_byindex(ip_set_id_t index); +extern void ip_set_nfnl_put(ip_set_id_t index); + +/* API for iptables set match, and SET target */ +extern int ip_set_add(ip_set_id_t id, const struct sk_buff *skb, + u8 family, u8 dim, u8 flags); +extern int ip_set_del(ip_set_id_t id, const struct sk_buff *skb, + u8 family, u8 dim, u8 flags); +extern int ip_set_test(ip_set_id_t id, const struct sk_buff *skb, + u8 family, u8 dim, u8 flags); + +/* Allocate members */ +static inline void * +ip_set_alloc(size_t size, gfp_t gfp_mask) +{ + void *members = NULL; + + if (size < KMALLOC_MAX_SIZE) + members = kzalloc(size, gfp_mask | __GFP_NOWARN); + + if (members) { + pr_debug("%p: allocated with kmalloc", members); + return members; + } + + members = __vmalloc(size, gfp_mask | __GFP_ZERO, PAGE_KERNEL); + if (!members) + return NULL; + pr_debug("%p: allocated with vmalloc", members); + + return members; +} + +static inline void +ip_set_free(void *members) +{ + pr_debug("%p: free with %s", members, + is_vmalloc_addr(members) ? "vfree" : "kfree"); + if (is_vmalloc_addr(members)) + vfree(members); + else + kfree(members); +} + +/* Ignore IPSET_ERR_EXIST errors if asked to do so? */ +static inline bool +ip_set_eexist(int ret, u32 flags) +{ + return ret == -IPSET_ERR_EXIST && (flags & IPSET_FLAG_EXIST); +} + +/* Useful converters */ +static inline u32 +ip_set_get_h32(const struct nlattr *attr) +{ + u32 value = nla_get_u32(attr); + + return attr->nla_type & NLA_F_NET_BYTEORDER ? ntohl(value) : value; +} + +static inline u16 +ip_set_get_h16(const struct nlattr *attr) +{ + u16 value = nla_get_u16(attr); + + return attr->nla_type & NLA_F_NET_BYTEORDER ? ntohs(value) : value; +} + +static inline u32 +ip_set_get_n32(const struct nlattr *attr) +{ + u32 value = nla_get_u32(attr); + + return attr->nla_type & NLA_F_NET_BYTEORDER ? value : htonl(value); +} + +static inline u16 +ip_set_get_n16(const struct nlattr *attr) +{ + u16 value = nla_get_u16(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) + +#define NLA_PUT_NET32(skb, type, value) \ + NLA_PUT_BE32(skb, type | NLA_F_NET_BYTEORDER, value) + +#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) +{ + return src ? ip_hdr(skb)->saddr : ip_hdr(skb)->daddr; +} + +static inline void +ip4addrptr(const struct sk_buff *skb, bool src, u32 *addr) +{ + *addr = src ? ip_hdr(skb)->saddr : ip_hdr(skb)->daddr; +} + +static inline void +ip6addrptr(const struct sk_buff *skb, bool src, struct in6_addr *addr) +{ + memcpy(addr, src ? &ipv6_hdr(skb)->saddr : &ipv6_hdr(skb)->daddr, + sizeof(*addr)); +} + +/* Calculate the bytes required to store the inclusive range of a-b */ +static inline int +bitmap_bytes(u32 a, u32 b) +{ + return 4 * ((((b - a + 8) / 8) + 3) / 4); +} + +/* Prefixlen maps */ +extern const union nf_inet_addr prefixlen_netmask_map[]; +extern const union nf_inet_addr prefixlen_hostmask_map[]; + +#define NETMASK(n) prefixlen_netmask_map[n].ip +#define NETMASK6(n) prefixlen_netmask_map[n].ip6 +#define HOSTMASK(n) prefixlen_hostmask_map[n].ip +#define HOSTMASK6(n) prefixlen_hostmask_map[n].ip6 + +/* Interface to iptables/ip6tables */ + +#define SO_IP_SET 83 + +union ip_set_name_index { + char name[IPSET_MAXNAMELEN]; + ip_set_id_t index; +}; + +#define IP_SET_OP_GET_BYNAME 0x00000006 /* Get set index by name */ +struct ip_set_req_get_set { + unsigned op; + unsigned version; + union ip_set_name_index set; +}; + +#define IP_SET_OP_GET_BYINDEX 0x00000007 /* Get set name by index */ +/* Uses ip_set_req_get_set */ + +#define IP_SET_OP_VERSION 0x00000100 /* Ask kernel version */ +struct ip_set_req_version { + unsigned op; + unsigned version; +}; + +#endif /* __KERNEL__ */ + +#endif /*_IP_SET_H */ diff --git a/kernel/include/linux/netfilter/ipset/ip_set_bitmap.h b/kernel/include/linux/netfilter/ipset/ip_set_bitmap.h new file mode 100644 index 0000000..61a9e87 --- /dev/null +++ b/kernel/include/linux/netfilter/ipset/ip_set_bitmap.h @@ -0,0 +1,31 @@ +#ifndef __IP_SET_BITMAP_H +#define __IP_SET_BITMAP_H + +/* 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, +}; + +#ifdef __KERNEL__ +#define IPSET_BITMAP_MAX_RANGE 0x0000FFFF + +/* Common functions */ + +static inline u32 +range_to_mask(u32 from, u32 to, u8 *bits) +{ + u32 mask = 0xFFFFFFFE; + + *bits = 32; + while (--(*bits) > 0 && mask && (to & mask) != from) + mask <<= 1; + + return mask; +} + +#endif /* __KERNEL__ */ + +#endif /* __IP_SET_BITMAP_H */ diff --git a/kernel/include/linux/netfilter/ipset/ip_set_chash.h b/kernel/include/linux/netfilter/ipset/ip_set_chash.h new file mode 100644 index 0000000..cd5e2f5 --- /dev/null +++ b/kernel/include/linux/netfilter/ipset/ip_set_chash.h @@ -0,0 +1,1164 @@ +#ifndef _IP_SET_CHASH_H +#define _IP_SET_CHASH_H + +#include +#include +#include + +/* 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 */ +#define CHASH_DEFAULT_ARRAY_SIZE 4 +/* 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 */ +}; + +struct htable { + u8 htable_bits; /* size of hash table == 2^htable_bits */ + struct slist htable[0]; /* hashtable of single linked lists */ +}; + +struct chash { + struct htable *table; /* the hash table */ + u32 maxelem; /* max elements in the hash */ + u32 elements; /* current element (vs timeout) */ + u32 initval; /* random jhash init value */ + u32 timeout; /* timeout value, if enabled */ + struct timer_list gc; /* garbage collection when timeout enabled */ + u8 array_size; /* number of elements in an array */ + u8 chain_limit; /* max number of arrays */ +#ifdef IP_SET_HASH_WITH_NETMASK + u8 netmask; /* netmask value for subnets to store */ +#endif +#ifdef IP_SET_HASH_WITH_NETS + 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) +{ + /* Assume that hashsize == 2^htable_bits */ + u8 bits = fls(hashsize - 1); + if (jhash_size(bits) != hashsize) + /* Round up to the first 2^n value */ + bits = fls(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 *h, u8 cidr, u8 host_mask) +{ + u8 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 (h->nets[i].cidr < cidr) + swap(h->nets[i].cidr, cidr); + } + if (i < host_mask) + h->nets[i].cidr = cidr; +} + +static inline void +del_cidr(struct chash *h, u8 cidr, u8 host_mask) +{ + u8 i; + + --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; + } + h->nets[i - 1].cidr = 0; +} +#endif + +/* Destroy the hashtable part of the set */ +static void +chash_destroy(struct htable *ht) +{ + struct slist *n, *tmp; + u32 i; + + for (i = 0; i < jhash_size(ht->htable_bits); i++) + slist_for_each_safe(n, tmp, &ht->htable[i]) + /* FIXME: use slab cache */ + kfree(n); + + ip_set_free(ht); +} + +/* Calculate the actual memory size of the set data */ +static size_t +chash_memsize(const struct chash *h, size_t dsize, u8 host_mask) +{ + struct slist *n; + u32 i; + struct htable *ht = h->table; + size_t memsize = sizeof(*h) +#ifdef IP_SET_HASH_WITH_NETS + + sizeof(struct chash_nets) * host_mask +#endif + + jhash_size(ht->htable_bits) * sizeof(struct slist); + + for (i = 0; i < jhash_size(ht->htable_bits); i++) + slist_for_each(n, &ht->htable[i]) + memsize += sizeof(struct slist) + + h->array_size * dsize; + + return memsize; +} + +/* Flush a hash type of set: destroy all elements */ +static void +ip_set_hash_flush(struct ip_set *set) +{ + struct chash *h = set->data; + struct htable *ht = h->table; + struct slist *n, *tmp; + u32 i; + + for (i = 0; i < jhash_size(ht->htable_bits); i++) { + slist_for_each_safe(n, tmp, &ht->htable[i]) + /* FIXME: slab cache */ + kfree(n); + ht->htable[i].next = NULL; + } +#ifdef IP_SET_HASH_WITH_NETS + memset(h->nets, 0, sizeof(struct chash_nets) + * 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) +{ + struct chash *h = set->data; + + if (with_timeout(h->timeout)) + del_timer_sync(&h->gc); + + chash_destroy(h->table); + kfree(h); + + set->data = NULL; +} + +#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) +#define type_pf_data_isnull TOKEN(TYPE, PF, _data_isnull) +#define type_pf_data_copy TOKEN(TYPE, PF, _data_copy) +#define type_pf_data_swap TOKEN(TYPE, PF, _data_swap) +#define type_pf_data_zero_out TOKEN(TYPE, PF, _data_zero_out) +#define type_pf_data_netmask TOKEN(TYPE, PF, _data_netmask) +#define type_pf_data_list TOKEN(TYPE, PF, _data_list) +#define type_pf_data_tlist TOKEN(TYPE, PF, _data_tlist) + +#define type_pf_elem TOKEN(TYPE, PF, _elem) +#define type_pf_telem TOKEN(TYPE, PF, _telem) +#define type_pf_data_timeout TOKEN(TYPE, PF, _data_timeout) +#define type_pf_data_expired TOKEN(TYPE, PF, _data_expired) +#define type_pf_data_swap_timeout TOKEN(TYPE, PF, _data_swap_timeout) +#define type_pf_data_timeout_set TOKEN(TYPE, PF, _data_timeout_set) + +#define type_pf_chash_readd TOKEN(TYPE, PF, _chash_readd) +#define type_pf_chash_del_elem TOKEN(TYPE, PF, _chash_del_elem) +#define type_pf_chash_add TOKEN(TYPE, PF, _chash_add) +#define type_pf_chash_del TOKEN(TYPE, PF, _chash_del) +#define type_pf_chash_test_cidrs TOKEN(TYPE, PF, _chash_test_cidrs) +#define type_pf_chash_test TOKEN(TYPE, PF, _chash_test) + +#define type_pf_chash_treadd TOKEN(TYPE, PF, _chash_treadd) +#define type_pf_chash_del_telem TOKEN(TYPE, PF, _chash_del_telem) +#define type_pf_chash_expire TOKEN(TYPE, PF, _chash_expire) +#define type_pf_chash_tadd TOKEN(TYPE, PF, _chash_tadd) +#define type_pf_chash_tdel TOKEN(TYPE, PF, _chash_tdel) +#define type_pf_chash_ttest_cidrs TOKEN(TYPE, PF, _chash_ttest_cidrs) +#define type_pf_chash_ttest TOKEN(TYPE, PF, _chash_ttest) + +#define type_pf_resize TOKEN(TYPE, PF, _resize) +#define type_pf_tresize TOKEN(TYPE, PF, _tresize) +#define type_pf_flush ip_set_hash_flush +#define type_pf_destroy ip_set_hash_destroy +#define type_pf_head TOKEN(TYPE, PF, _head) +#define type_pf_list TOKEN(TYPE, PF, _list) +#define type_pf_tlist TOKEN(TYPE, PF, _tlist) +#define type_pf_same_set TOKEN(TYPE, PF, _same_set) +#define type_pf_kadt TOKEN(TYPE, PF, _kadt) +#define type_pf_uadt TOKEN(TYPE, PF, _uadt) +#define type_pf_gc TOKEN(TYPE, PF, _gc) +#define type_pf_gc_init TOKEN(TYPE, PF, _gc_init) +#define type_pf_variant TOKEN(TYPE, PF, _variant) +#define type_pf_tvariant TOKEN(TYPE, PF, _tvariant) + +/* 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 htable *ht, + const struct type_pf_elem *value, + gfp_t gfp_flags) +{ + struct slist *n, *prev; + struct type_pf_elem *data; + void *tmp; + int i = 0, j = 0; + u32 hash = JHASH2(value, h->initval, ht->htable_bits); + + slist_for_each_prev(prev, n, &ht->htable[hash]) { + for (i = 0; i < h->array_size; i++) { + data = chash_data(n, i); + if (type_pf_data_isnull(data)) { + tmp = n; + goto found; + } + } + j++; + } + if (j < h->chain_limit) { + tmp = kzalloc(h->array_size * sizeof(struct type_pf_elem) + + sizeof(struct slist), gfp_flags); + if (!tmp) + return -ENOMEM; + prev->next = (struct slist *) tmp; + data = chash_data(tmp, 0); + } else { + /* Trigger rehashing */ + return -EAGAIN; + } +found: + type_pf_data_copy(data, value); + 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; /* Index in array */ + + if (n->next != NULL) { + for (prev = n, tmp = n->next; + tmp->next != NULL; + prev = tmp, tmp = tmp->next) + /* Find last array */; + j = 0; + } else { + /* Already at last array */ + tmp = n; + j = i; + } + /* Find last non-empty element */ + for (; j < h->array_size - 1; j++) + if (type_pf_data_isnull(chash_data(tmp, j + 1))) + break; + + if (!(tmp == n && i == j)) + type_pf_data_swap(data, chash_data(tmp, j)); + +#ifdef IP_SET_HASH_WITH_NETS + del_cidr(h, data->cidr, HOST_MASK); +#endif + if (j == 0) { + prev->next = NULL; + kfree(tmp); + } else + type_pf_data_zero_out(chash_data(tmp, j)); + + 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) +{ + struct chash *h = set->data; + struct htable *ht, *orig = h->table; + u8 htable_bits = orig->htable_bits; + struct slist *n; + const struct type_pf_elem *data; + u32 i, j; + int ret; + +retry: + ret = i = 0; + htable_bits++; + if (!htable_bits) + /* In case we have plenty of memory :-) */ + return -IPSET_ERR_HASH_FULL; + ht = ip_set_alloc(sizeof(*ht) + + jhash_size(htable_bits) * sizeof(struct slist), + GFP_KERNEL); + if (!ht) + return -ENOMEM; + ht->htable_bits = htable_bits; + + read_lock_bh(&set->lock); +next_slot: + for (; i < jhash_size(orig->htable_bits); i++) { + slist_for_each(n, &orig->htable[i]) { + for (j = 0; j < h->array_size; j++) { + data = chash_data(n, j); + if (type_pf_data_isnull(data)) { + i++; + goto next_slot; + } + ret = type_pf_chash_readd(h, ht, + data, gfp_flags); + if (ret < 0) { + read_unlock_bh(&set->lock); + chash_destroy(ht); + if (ret == -EAGAIN) + goto retry; + return ret; + } + } + } + } + + h->table = ht; + read_unlock_bh(&set->lock); + + /* Give time to other users of the set */ + synchronize_net(); + + chash_destroy(orig); + + 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) +{ + struct chash *h = set->data; + const struct type_pf_elem *d = value; + struct slist *n, *prev; + struct htable *ht = h->table; + struct type_pf_elem *data; + void *tmp; + int i = 0, j = 0; + u32 hash; + + if (h->elements >= h->maxelem) + return -IPSET_ERR_HASH_FULL; + + hash = JHASH2(value, h->initval, ht->htable_bits); + slist_for_each_prev(prev, n, &ht->htable[hash]) { + for (i = 0; i < h->array_size; i++) { + data = chash_data(n, i); + if (type_pf_data_isnull(data)) { + tmp = n; + goto found; + } + if (type_pf_data_equal(data, d)) + return -IPSET_ERR_EXIST; + } + j++; + } + if (j < h->chain_limit) { + tmp = kzalloc(h->array_size * sizeof(struct type_pf_elem) + + sizeof(struct slist), gfp_flags); + if (!tmp) + return -ENOMEM; + prev->next = (struct slist *) tmp; + data = chash_data(tmp, 0); + } else { + /* Rehashing */ + return -EAGAIN; + } +found: + type_pf_data_copy(data, d); +#ifdef IP_SET_HASH_WITH_NETS + 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) +{ + struct chash *h = set->data; + const struct type_pf_elem *d = value; + struct htable *ht = h->table; + struct slist *n, *prev; + int i; + struct type_pf_elem *data; + u32 hash = JHASH2(value, h->initval, ht->htable_bits); + + slist_for_each_prev(prev, n, &ht->htable[hash]) + for (i = 0; i < h->array_size; i++) { + data = chash_data(n, i); + if (type_pf_data_isnull(data)) + return -IPSET_ERR_EXIST; + if (type_pf_data_equal(data, d)) { + type_pf_chash_del_elem(h, prev, n, i); + return 0; + } + } + + return -IPSET_ERR_EXIST; +} + +#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, + gfp_t gfp_flags, u32 timeout) +{ + struct chash *h = set->data; + struct htable *ht = h->table; + struct slist *n; + const struct type_pf_elem *data; + int i, j = 0; + u32 hash; + u8 host_mask = SET_HOST_MASK(set->family); + +retry: + pr_debug("test by nets"); + for (; j < host_mask && h->nets[j].cidr; j++) { + type_pf_data_netmask(d, h->nets[j].cidr); + hash = JHASH2(d, h->initval, ht->htable_bits); + slist_for_each(n, &ht->htable[hash]) + for (i = 0; i < h->array_size; i++) { + data = chash_data(n, i); + if (type_pf_data_isnull(data)) { + j++; + goto retry; + } + if (type_pf_data_equal(data, d)) + return 1; + } + } + return 0; +} +#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) +{ + struct chash *h = set->data; + struct htable *ht = h->table; + struct type_pf_elem *d = value; + struct slist *n; + const struct type_pf_elem *data; + int i; + u32 hash; + +#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 + + hash = JHASH2(d, h->initval, ht->htable_bits); + slist_for_each(n, &ht->htable[hash]) + for (i = 0; i < h->array_size; i++) { + data = chash_data(n, i); + if (type_pf_data_isnull(data)) + return 0; + if (type_pf_data_equal(data, d)) + return 1; + } + 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) +{ + const struct chash *h = set->data; + struct nlattr *nested; + size_t memsize; + + read_lock_bh(&set->lock); + memsize = chash_memsize(h, with_timeout(h->timeout) + ? sizeof(struct type_pf_telem) + : sizeof(struct type_pf_elem), + set->family == AF_INET ? 32 : 128); + read_unlock_bh(&set->lock); + + nested = ipset_nest_start(skb, IPSET_ATTR_DATA); + if (!nested) + goto nla_put_failure; + NLA_PUT_NET32(skb, IPSET_ATTR_HASHSIZE, + htonl(jhash_size(h->table->htable_bits))); + NLA_PUT_NET32(skb, IPSET_ATTR_MAXELEM, htonl(h->maxelem)); +#ifdef IP_SET_HASH_WITH_NETMASK + if (h->netmask != HOST_MASK) + NLA_PUT_U8(skb, IPSET_ATTR_NETMASK, h->netmask); +#endif + NLA_PUT_NET32(skb, IPSET_ATTR_REFERENCES, + htonl(atomic_read(&set->ref) - 1)); + NLA_PUT_NET32(skb, IPSET_ATTR_MEMSIZE, htonl(memsize)); + if (with_timeout(h->timeout)) + NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT, htonl(h->timeout)); + ipset_nest_end(skb, nested); + + return 0; +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) +{ + const struct chash *h = set->data; + const struct htable *ht = h->table; + struct nlattr *atd, *nested; + struct slist *n; + const struct type_pf_elem *data; + u32 first = cb->args[2]; + /* We assume that one hash bucket fills into one page */ + void *incomplete; + int i; + + atd = ipset_nest_start(skb, IPSET_ATTR_ADT); + if (!atd) + return -EFAULT; + pr_debug("list hash set %s", set->name); + for (; cb->args[2] < jhash_size(ht->htable_bits); cb->args[2]++) { + incomplete = skb_tail_pointer(skb); + slist_for_each(n, &ht->htable[cb->args[2]]) { + for (i = 0; i < h->array_size; i++) { + data = chash_data(n, i); + if (type_pf_data_isnull(data)) + break; + pr_debug("list hash %lu slist %p i %u", + cb->args[2], n, i); + nested = ipset_nest_start(skb, IPSET_ATTR_DATA); + if (!nested) { + if (cb->args[2] == first) { + nla_nest_cancel(skb, atd); + return -EFAULT; + } else + goto nla_put_failure; + } + if (type_pf_data_list(skb, data)) + goto nla_put_failure; + ipset_nest_end(skb, nested); + } + } + } + ipset_nest_end(skb, atd); + /* Set listing finished */ + cb->args[2] = 0; + + return 0; + +nla_put_failure: + nlmsg_trim(skb, incomplete); + ipset_nest_end(skb, atd); + if (unlikely(first == cb->args[2])) { + pr_warn("Can't list set %s: one bucket does not fit into " + "a message. Please report it!\n", set->name); + cb->args[2] = 0; + } + return 0; +} + +static int +type_pf_kadt(struct ip_set *set, const struct sk_buff * skb, + enum ipset_adt adt, u8 pf, u8 dim, u8 flags); +static int +type_pf_uadt(struct ip_set *set, struct nlattr *head, int len, + enum ipset_adt adt, u32 *lineno, u32 flags); + +static const struct ip_set_type_variant type_pf_variant __read_mostly = { + .kadt = type_pf_kadt, + .uadt = type_pf_uadt, + .adt = { + [IPSET_ADD] = type_pf_chash_add, + [IPSET_DEL] = type_pf_chash_del, + [IPSET_TEST] = type_pf_chash_test, + }, + .destroy = type_pf_destroy, + .flush = type_pf_flush, + .head = type_pf_head, + .list = type_pf_list, + .resize = type_pf_resize, + .same_set = type_pf_same_set, +}; + +/* Flavour with timeout support */ + +#define chash_tdata(n, i) \ +(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) +{ + const struct type_pf_telem *tdata = + (const struct type_pf_telem *) data; + + return tdata->timeout; +} + +static inline bool +type_pf_data_expired(const struct type_pf_elem *data) +{ + const struct type_pf_telem *tdata = + (const struct type_pf_telem *) data; + + return ip_set_timeout_expired(tdata->timeout); +} + +static inline void +type_pf_data_swap_timeout(struct type_pf_elem *src, + struct type_pf_elem *dst) +{ + struct type_pf_telem *x = (struct type_pf_telem *) src; + struct type_pf_telem *y = (struct type_pf_telem *) dst; + + swap(x->timeout, y->timeout); +} + +static inline void +type_pf_data_timeout_set(struct type_pf_elem *data, u32 timeout) +{ + struct type_pf_telem *tdata = (struct type_pf_telem *) data; + + tdata->timeout = ip_set_timeout_set(timeout); +} + +static int +type_pf_chash_treadd(struct chash *h, struct htable *ht, + const struct type_pf_elem *value, + gfp_t gfp_flags, u32 timeout) +{ + struct slist *n, *prev; + struct type_pf_elem *data; + void *tmp; + int i = 0, j = 0; + u32 hash = JHASH2(value, h->initval, ht->htable_bits); + + slist_for_each_prev(prev, n, &ht->htable[hash]) { + for (i = 0; i < h->array_size; i++) { + data = chash_tdata(n, i); + if (type_pf_data_isnull(data)) { + tmp = n; + goto found; + } + } + j++; + } + if (j < h->chain_limit) { + tmp = kzalloc(h->array_size * sizeof(struct type_pf_telem) + + sizeof(struct slist), gfp_flags); + if (!tmp) + return -ENOMEM; + prev->next = (struct slist *) tmp; + data = chash_tdata(tmp, 0); + } else { + /* Trigger rehashing */ + return -EAGAIN; + } +found: + type_pf_data_copy(data, value); + type_pf_data_timeout_set(data, timeout); + return 0; +} + +static void +type_pf_chash_del_telem(struct chash *h, struct slist *prev, + struct slist *n, int i) +{ + struct type_pf_elem *d, *data = chash_tdata(n, i); + struct slist *tmp; + int j; /* Index in array */ + + pr_debug("del %u", i); + if (n->next != NULL) { + for (prev = n, tmp = n->next; + tmp->next != NULL; + prev = tmp, tmp = tmp->next) + /* Find last array */; + j = 0; + } else { + /* Already at last array */ + tmp = n; + j = i; + } + /* Find last non-empty element */ + for (; j < h->array_size - 1; j++) + if (type_pf_data_isnull(chash_tdata(tmp, j + 1))) + break; + + d = chash_tdata(tmp, j); + if (!(tmp == n && i == j)) { + type_pf_data_swap(data, d); + type_pf_data_swap_timeout(data, d); + } +#ifdef IP_SET_HASH_WITH_NETS + del_cidr(h, data->cidr, HOST_MASK); +#endif + if (j == 0) { + prev->next = NULL; + kfree(tmp); + } else + type_pf_data_zero_out(d); + + h->elements--; +} + +/* Delete expired elements from the hashtable */ +static void +type_pf_chash_expire(struct chash *h) +{ + struct htable *ht = h->table; + struct slist *n, *prev; + struct type_pf_elem *data; + u32 i; + int j; + + for (i = 0; i < jhash_size(ht->htable_bits); i++) + slist_for_each_prev(prev, n, &ht->htable[i]) + for (j = 0; j < h->array_size; j++) { + data = chash_tdata(n, j); + if (type_pf_data_isnull(data)) + break; + if (type_pf_data_expired(data)) { + pr_debug("expire %u/%u", i, j); + type_pf_chash_del_telem(h, prev, n, j); + } + } +} + +static int +type_pf_tresize(struct ip_set *set, gfp_t gfp_flags, bool retried) +{ + struct chash *h = set->data; + struct htable *ht, *orig = h->table; + u8 htable_bits = orig->htable_bits; + struct slist *n; + const struct type_pf_elem *data; + u32 i, j; + int ret; + + /* Try to cleanup once */ + if (!retried) { + i = h->elements; + write_lock_bh(&set->lock); + type_pf_chash_expire(set->data); + write_unlock_bh(&set->lock); + if (h->elements < i) + return 0; + } + +retry: + ret = i = 0; + htable_bits++; + if (!htable_bits) + /* In case we have plenty of memory :-) */ + return -IPSET_ERR_HASH_FULL; + ht = ip_set_alloc(sizeof(*ht) + + jhash_size(htable_bits) * sizeof(struct slist), + GFP_KERNEL); + if (!ht) + return -ENOMEM; + ht->htable_bits = htable_bits; + + read_lock_bh(&set->lock); +next_slot: + for (; i < jhash_size(orig->htable_bits); i++) { + slist_for_each(n, &orig->htable[i]) { + for (j = 0; j < h->array_size; j++) { + data = chash_tdata(n, j); + if (type_pf_data_isnull(data)) { + i++; + goto next_slot; + } + ret = type_pf_chash_treadd(h, ht, + data, gfp_flags, + type_pf_data_timeout(data)); + if (ret < 0) { + read_unlock_bh(&set->lock); + chash_destroy(ht); + if (ret == -EAGAIN) + goto retry; + return ret; + } + } + } + } + + h->table = ht; + read_unlock_bh(&set->lock); + + /* Give time to other users of the set */ + synchronize_net(); + + chash_destroy(orig); + + return 0; +} + +static int +type_pf_chash_tadd(struct ip_set *set, void *value, + gfp_t gfp_flags, u32 timeout) +{ + struct chash *h = set->data; + const struct type_pf_elem *d = value; + struct slist *n, *prev; + struct htable *ht = h->table; + struct type_pf_elem *data; + void *tmp; + int i = 0, j = 0; + u32 hash; + + if (h->elements >= h->maxelem) + /* FIXME: when set is full, we slow down here */ + type_pf_chash_expire(h); + if (h->elements >= h->maxelem) + return -IPSET_ERR_HASH_FULL; + + hash = JHASH2(d, h->initval, ht->htable_bits); + slist_for_each_prev(prev, n, &ht->htable[hash]) { + for (i = 0; i < h->array_size; i++) { + data = chash_tdata(n, i); + if (type_pf_data_isnull(data) + || type_pf_data_expired(data)) { + tmp = n; + goto found; + } + if (type_pf_data_equal(data, d)) + return -IPSET_ERR_EXIST; + } + j++; + } + if (j < h->chain_limit) { + tmp = kzalloc(h->array_size * sizeof(struct type_pf_telem) + + sizeof(struct slist), gfp_flags); + if (!tmp) + return -ENOMEM; + prev->next = (struct slist *) tmp; + data = chash_tdata(tmp, 0); + } else { + /* Rehashing */ + return -EAGAIN; + } +found: + if (type_pf_data_isnull(data)) + h->elements++; +#ifdef IP_SET_HASH_WITH_NETS + 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; +} + +static int +type_pf_chash_tdel(struct ip_set *set, void *value, + gfp_t gfp_flags, u32 timeout) +{ + struct chash *h = set->data; + struct htable *ht = h->table; + const struct type_pf_elem *d = value; + struct slist *n, *prev; + int i, ret = 0; + struct type_pf_elem *data; + u32 hash = JHASH2(value, h->initval, ht->htable_bits); + + slist_for_each_prev(prev, n, &ht->htable[hash]) + for (i = 0; i < h->array_size; i++) { + data = chash_tdata(n, i); + if (type_pf_data_isnull(data)) + return -IPSET_ERR_EXIST; + if (type_pf_data_equal(data, d)) { + if (type_pf_data_expired(data)) + ret = -IPSET_ERR_EXIST; + type_pf_chash_del_telem(h, prev, n, i); + return ret; + } + } + + return -IPSET_ERR_EXIST; +} + +#ifdef IP_SET_HASH_WITH_NETS +static inline int +type_pf_chash_ttest_cidrs(struct ip_set *set, + struct type_pf_elem *d, + gfp_t gfp_flags, u32 timeout) +{ + struct chash *h = set->data; + struct htable *ht = h->table; + struct type_pf_elem *data; + struct slist *n; + int i, j = 0; + u32 hash; + u8 host_mask = SET_HOST_MASK(set->family); + +retry: + for (; j < host_mask && h->nets[j].cidr; j++) { + type_pf_data_netmask(d, h->nets[j].cidr); + hash = JHASH2(d, h->initval, ht->htable_bits); + slist_for_each(n, &ht->htable[hash]) + for (i = 0; i < h->array_size; i++) { + data = chash_tdata(n, i); + if (type_pf_data_isnull(data)) { + j++; + goto retry; + } + if (type_pf_data_equal(data, d)) + return !type_pf_data_expired(data); + } + } + return 0; +} +#endif + +static inline int +type_pf_chash_ttest(struct ip_set *set, void *value, + gfp_t gfp_flags, u32 timeout) +{ + struct chash *h = set->data; + struct htable *ht = h->table; + struct type_pf_elem *data, *d = value; + struct slist *n; + int i; + u32 hash; + +#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 + hash = JHASH2(d, h->initval, ht->htable_bits); + slist_for_each(n, &ht->htable[hash]) + for (i = 0; i < h->array_size; i++) { + data = chash_tdata(n, i); + if (type_pf_data_isnull(data)) + return 0; + if (type_pf_data_equal(data, d)) + return !type_pf_data_expired(data); + } + return 0; +} + +static int +type_pf_tlist(struct ip_set *set, + struct sk_buff *skb, struct netlink_callback *cb) +{ + const struct chash *h = set->data; + const struct htable *ht = h->table; + struct nlattr *atd, *nested; + struct slist *n; + const struct type_pf_elem *data; + u32 first = cb->args[2]; + /* We assume that one hash bucket fills into one page */ + void *incomplete; + int i; + + atd = ipset_nest_start(skb, IPSET_ATTR_ADT); + if (!atd) + return -EFAULT; + for (; cb->args[2] < jhash_size(ht->htable_bits); cb->args[2]++) { + incomplete = skb_tail_pointer(skb); + slist_for_each(n, &ht->htable[cb->args[2]]) { + for (i = 0; i < h->array_size; i++) { + data = chash_tdata(n, i); + pr_debug("list %p %u", n, i); + if (type_pf_data_isnull(data)) + break; + if (type_pf_data_expired(data)) + continue; + pr_debug("do list %p %u", n, i); + nested = ipset_nest_start(skb, IPSET_ATTR_DATA); + if (!nested) { + if (cb->args[2] == first) { + nla_nest_cancel(skb, atd); + return -EFAULT; + } else + goto nla_put_failure; + } + if (type_pf_data_tlist(skb, data)) + goto nla_put_failure; + ipset_nest_end(skb, nested); + } + } + } + ipset_nest_end(skb, atd); + /* Set listing finished */ + cb->args[2] = 0; + + return 0; + +nla_put_failure: + nlmsg_trim(skb, incomplete); + ipset_nest_end(skb, atd); + if (unlikely(first == cb->args[2])) { + pr_warn("Can't list set %s: one bucket does not fit into " + "a message. Please report it!\n", set->name); + cb->args[2] = 0; + } + return 0; +} + +static const struct ip_set_type_variant type_pf_tvariant __read_mostly = { + .kadt = type_pf_kadt, + .uadt = type_pf_uadt, + .adt = { + [IPSET_ADD] = type_pf_chash_tadd, + [IPSET_DEL] = type_pf_chash_tdel, + [IPSET_TEST] = type_pf_chash_ttest, + }, + .destroy = type_pf_destroy, + .flush = type_pf_flush, + .head = type_pf_head, + .list = type_pf_tlist, + .resize = type_pf_tresize, + .same_set = type_pf_same_set, +}; + +static void +type_pf_gc(unsigned long ul_set) +{ + struct ip_set *set = (struct ip_set *) ul_set; + struct chash *h = set->data; + + pr_debug("called"); + write_lock_bh(&set->lock); + type_pf_chash_expire(h); + write_unlock_bh(&set->lock); + + h->gc.expires = jiffies + IPSET_GC_PERIOD(h->timeout) * HZ; + add_timer(&h->gc); +} + +static inline void +type_pf_gc_init(struct ip_set *set) +{ + struct chash *h = set->data; + + init_timer(&h->gc); + h->gc.data = (unsigned long) 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)); +} + +#undef type_pf_data_equal +#undef type_pf_data_isnull +#undef type_pf_data_copy +#undef type_pf_data_swap +#undef type_pf_data_zero_out +#undef type_pf_data_list +#undef type_pf_data_tlist + +#undef type_pf_elem +#undef type_pf_telem +#undef type_pf_data_timeout +#undef type_pf_data_expired +#undef type_pf_data_swap_timeout +#undef type_pf_data_netmask +#undef type_pf_data_timeout_set + +#undef type_pf_chash_readd +#undef type_pf_chash_del_elem +#undef type_pf_chash_add +#undef type_pf_chash_del +#undef type_pf_chash_test_cidrs +#undef type_pf_chash_test + +#undef type_pf_chash_treadd +#undef type_pf_chash_del_telem +#undef type_pf_chash_expire +#undef type_pf_chash_tadd +#undef type_pf_chash_tdel +#undef type_pf_chash_ttest_cidrs +#undef type_pf_chash_ttest + +#undef type_pf_resize +#undef type_pf_tresize +#undef type_pf_flush +#undef type_pf_destroy +#undef type_pf_head +#undef type_pf_list +#undef type_pf_tlist +#undef type_pf_same_set +#undef type_pf_kadt +#undef type_pf_uadt +#undef type_pf_gc +#undef type_pf_gc_init +#undef type_pf_variant +#undef type_pf_tvariant diff --git a/kernel/include/linux/netfilter/ipset/ip_set_getport.h b/kernel/include/linux/netfilter/ipset/ip_set_getport.h new file mode 100644 index 0000000..1597fa9 --- /dev/null +++ b/kernel/include/linux/netfilter/ipset/ip_set_getport.h @@ -0,0 +1,126 @@ +#ifndef _IP_SET_GETPORT_H +#define _IP_SET_GETPORT_H + +#ifdef __KERNEL__ +#include +#include +#include +#include + +#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) +{ + switch (protocol) { + case IPPROTO_TCP: { + struct tcphdr _tcph; + const struct tcphdr *th; + + th = skb_header_pointer(skb, protooff, sizeof(_tcph), &_tcph); + if (th == NULL) + /* No choice either */ + return false; + + *port = src ? th->source : th->dest; + break; + } + case IPPROTO_UDP: { + struct udphdr _udph; + const struct udphdr *uh; + + uh = skb_header_pointer(skb, protooff, sizeof(_udph), &_udph); + if (uh == NULL) + /* No choice either */ + return false; + + *port = src ? uh->source : uh->dest; + break; + } + 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; + } + *proto = protocol; + + return true; +} + +static inline bool +get_ip4_port(const struct sk_buff *skb, bool src, u16 *port, u8 *proto) +{ + const struct iphdr *iph = ip_hdr(skb); + unsigned int protooff = ip_hdrlen(skb); + int protocol = iph->protocol; + + /* See comments at tcp_match in ip_tables.c */ + if (ntohs(iph->frag_off) & IP_OFFSET) + return false; + + return get_port(skb, protocol, protooff, src, port, proto); +} + +static inline bool +get_ip6_port(const struct sk_buff *skb, bool src, u16 *port, u8 *proto) +{ + unsigned int protooff = 0; + int protocol; + unsigned short fragoff; + + protocol = ipv6_find_hdr(skb, &protooff, -1, &fragoff); + if (protocol < 0 || fragoff) + 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) +{ + 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__ */ + +#endif /*_IP_SET_GETPORT_H*/ diff --git a/kernel/include/linux/netfilter/ipset/ip_set_hash.h b/kernel/include/linux/netfilter/ipset/ip_set_hash.h new file mode 100644 index 0000000..b86f15c --- /dev/null +++ b/kernel/include/linux/netfilter/ipset/ip_set_hash.h @@ -0,0 +1,26 @@ +#ifndef __IP_SET_HASH_H +#define __IP_SET_HASH_H + +/* 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, +}; + +#ifdef __KERNEL__ + +#define IPSET_DEFAULT_HASHSIZE 1024 +#define IPSET_MIMINAL_HASHSIZE 64 +#define IPSET_DEFAULT_MAXELEM 65536 +#define IPSET_DEFAULT_PROBES 4 +#define IPSET_DEFAULT_RESIZE 100 + +#endif /* __KERNEL__ */ + +#endif /* __IP_SET_HASH_H */ diff --git a/kernel/include/linux/netfilter/ipset/ip_set_jhash.h b/kernel/include/linux/netfilter/ipset/ip_set_jhash.h new file mode 100644 index 0000000..d5e0d6d --- /dev/null +++ b/kernel/include/linux/netfilter/ipset/ip_set_jhash.h @@ -0,0 +1,121 @@ +#ifndef _LINUX_JHASH_H +#define _LINUX_JHASH_H +/* jhash.c: Jenkins hash support. + * + * Copyright (C) 2006. Bob Jenkins (bob_jenkins@burtleburtle.net) + * + * http://burtleburtle.net/bob/hash/ + * + * These are the credits from Bob's sources: + * + * lookup3.c, by Bob Jenkins, May 2006, Public Domain. + * + * These are functions for producing 32-bit hashes for hash table lookup. + * hashword(), hashlittle(), hashlittle2(), hashbig(), mix(), and final() + * are externally useful functions. Routines to test the hash are included + * if SELF_TEST is defined. You can use this free for any purpose. It's in + * the public domain. It has no warranty. + * + * Copyright (C) 2009-2010 Jozsef Kadlecsik (kadlec@blackhole.kfki.hu) + * + * I've modified Bob's hash to be useful in the Linux kernel, and + * any bugs present are my fault. The generic jhash is left out intentionally. + * Jozsef + */ +#ifdef __KERNEL__ +#include + +/* Best hash sizes are of power of two */ +#define jhash_size(n) ((u32)1<<(n)) +/* Mask the hash value, i.e (value & jhash_mask(n)) instead of (value % n) */ +#define jhash_mask(n) (jhash_size(n)-1) + +/* __jhash_rot - rotate 32 bit */ +#define __jhash_rot(x,k) (((x)<<(k)) | ((x)>>(32-(k)))) + +/* __jhash_mix -- mix 3 32-bit values reversibly. */ +#define __jhash_mix(a,b,c) \ +{ \ + a -= c; a ^= __jhash_rot(c, 4); c += b; \ + b -= a; b ^= __jhash_rot(a, 6); a += c; \ + c -= b; c ^= __jhash_rot(b, 8); b += a; \ + a -= c; a ^= __jhash_rot(c,16); c += b; \ + b -= a; b ^= __jhash_rot(a,19); a += c; \ + c -= b; c ^= __jhash_rot(b, 4); b += a; \ +} + +/* __jhash_final - final mixing of 3 32-bit values (a,b,c) into c */ +#define __jhash_final(a,b,c) \ +{ \ + c ^= b; c -= __jhash_rot(b,14); \ + a ^= c; a -= __jhash_rot(c,11); \ + b ^= a; b -= __jhash_rot(a,25); \ + c ^= b; c -= __jhash_rot(b,16); \ + a ^= c; a -= __jhash_rot(c,4); \ + b ^= a; b -= __jhash_rot(a,14); \ + c ^= b; c -= __jhash_rot(b,24); \ +} + +#define JHASH_INITVAL 0xdeadbeef + +/* jhash2 - hash an array of u32's + * @k: the key which must be an array of u32's + * @length: the number of u32's in the key + * @initval: the previous hash, or an arbitray value + * + * Returns the hash value of the key. + */ +static inline u32 jhash2(const u32 *k, u32 length, u32 initval) +{ + u32 a, b, c; + + /* Set up the internal state */ + a = b = c = JHASH_INITVAL + (length<<2) + initval; + + /* Handle most of the key */ + while (length > 3) { + a += k[0]; + b += k[1]; + c += k[2]; + __jhash_mix(a,b,c); + length -= 3; + k += 3; + } + + /* Handle the last 3 u32's: all the case statements fall through */ + switch(length) { + case 3: c += k[2]; + case 2: b += k[1]; + case 1: a += k[0]; + __jhash_final(a,b,c); + case 0: /* Nothing left to add */ + break; + } + + return c; +} + +/* jhash_3words - hash exactly 3, 2 or 1 word(s) */ +static inline u32 jhash_3words(u32 a, u32 b, u32 c, u32 initval) +{ + a += JHASH_INITVAL; + b += JHASH_INITVAL; + c += initval; + + __jhash_final(a,b,c); + + return c; +} +static inline u32 jhash_2words(u32 a, u32 b, u32 initval) +{ + return jhash_3words(a, b, 0, initval); +} + +static inline u32 jhash_1word(u32 a, u32 initval) +{ + return jhash_3words(a, 0, 0, initval); +} + +#endif /* __KERNEL__ */ + +#endif /* _LINUX_JHASH_H */ diff --git a/kernel/include/linux/netfilter/ipset/ip_set_kernel.h b/kernel/include/linux/netfilter/ipset/ip_set_kernel.h new file mode 100644 index 0000000..d770589 --- /dev/null +++ b/kernel/include/linux/netfilter/ipset/ip_set_kernel.h @@ -0,0 +1,15 @@ +#ifndef _IP_SET_KERNEL_H +#define _IP_SET_KERNEL_H + +#ifdef __KERNEL__ + +#ifdef CONFIG_DEBUG_KERNEL +/* Complete debug messages */ +#define pr_fmt(fmt) "%s %s[%i]: " fmt "\n", __FILE__, __func__, __LINE__ +#endif + +#include + +#endif /* __KERNEL__ */ + +#endif /*_IP_SET_H */ diff --git a/kernel/include/linux/netfilter/ipset/ip_set_list.h b/kernel/include/linux/netfilter/ipset/ip_set_list.h new file mode 100644 index 0000000..40a63f3 --- /dev/null +++ b/kernel/include/linux/netfilter/ipset/ip_set_list.h @@ -0,0 +1,27 @@ +#ifndef __IP_SET_LIST_H +#define __IP_SET_LIST_H + +/* 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, +}; + +#ifdef __KERNEL__ + +#define IP_SET_LIST_DEFAULT_SIZE 8 +#define IP_SET_LIST_MIN_SIZE 4 + +#endif /* __KERNEL__ */ + +#endif /* __IP_SET_LIST_H */ diff --git a/kernel/include/linux/netfilter/ipset/ip_set_slist.h b/kernel/include/linux/netfilter/ipset/ip_set_slist.h new file mode 100644 index 0000000..e472e43 --- /dev/null +++ b/kernel/include/linux/netfilter/ipset/ip_set_slist.h @@ -0,0 +1,89 @@ +#ifndef _IP_SET_SLIST_H +#define _IP_SET_SLIST_H + +#include +#include +#include + +/* + * Single linked lists with a single pointer. + * Mostly useful for hash tables where the two pointer list head + * and list node is too wasteful. + */ + +struct slist { + struct slist *next; +}; + +#define SLIST(name) struct slist name = { .next = NULL } +#define INIT_SLIST(ptr) ((ptr)->next = NULL) + +#define slist_entry(ptr, type, member) container_of(ptr, type, member) + +#define slist_for_each(pos, head) \ + for (pos = (head)->next; pos && ({ prefetch(pos->next); 1; }); \ + pos = pos->next) + +#define slist_for_each_prev(prev, pos, head) \ + for (prev = head, pos = (head)->next; \ + pos && ({ prefetch(pos->next); 1; }); \ + prev = pos, pos = pos->next) + +#define slist_for_each_safe(pos, n, head) \ + for (pos = (head)->next; pos && ({ n = pos->next; 1; }); \ + pos = n) + +/** + * slist_for_each_entry - iterate over list of given type + * @tpos: the type * to use as a loop cursor. + * @pos: the &struct slist to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the slist within the struct. + */ +#define slist_for_each_entry(tpos, pos, head, member) \ + for (pos = (head)->next; \ + pos && ({ prefetch(pos->next); 1; }) && \ + ({ tpos = slist_entry(pos, typeof(*tpos), member); 1; });\ + pos = pos->next) + +/** + * 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. + */ +#define slist_for_each_entry_continue(tpos, pos, member) \ + for (pos = (pos)->next; \ + pos && ({ prefetch(pos->next); 1; }) && \ + ({ tpos = slist_entry(pos, typeof(*tpos), member); 1; });\ + pos = pos->next) + +/** + * 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. + */ +#define slist_for_each_entry_from(tpos, pos, member) \ + for (; pos && ({ prefetch(pos->next); 1; }) && \ + ({ tpos = slist_entry(pos, typeof(*tpos), member); 1; });\ + pos = pos->next) + +/** + * slist_for_each_entry_safe - iterate over list of given type safe against + * removal of list entry + * @tpos: the type * to use as a loop cursor. + * @pos: the &struct slist to use as a loop cursor. + * @n: another &struct slist to use as temporary storage + * @head: the head for your list. + * @member: the name of the slist within the struct. + */ +#define slist_for_each_entry_safe(tpos, pos, n, head, member) \ + for (pos = (head)->next; \ + pos && ({ n = pos->next; 1; }) && \ + ({ tpos = slist_entry(pos, typeof(*tpos), member); 1; });\ + pos = n) + +#endif /* _IP_SET_SLIST_H */ diff --git a/kernel/include/linux/netfilter/ipset/ip_set_timeout.h b/kernel/include/linux/netfilter/ipset/ip_set_timeout.h new file mode 100644 index 0000000..519d84f --- /dev/null +++ b/kernel/include/linux/netfilter/ipset/ip_set_timeout.h @@ -0,0 +1,127 @@ +#ifndef _IP_SET_TIMEOUT_H +#define _IP_SET_TIMEOUT_H + +/* Copyright (C) 2003-2010 Jozsef Kadlecsik + * + * 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__ + +/* How often should the gc be run by default */ +#define IPSET_GC_TIME (3 * 60) + +/* Timeout period depending on the timeout value of the given set */ +#define IPSET_GC_PERIOD(timeout) \ + ((timeout/3) ? min_t(u32, (timeout)/3, IPSET_GC_TIME) : 1) + +/* 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) + +static inline unsigned int +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 */ +#define IPSET_ELEM_PERMANENT (UINT_MAX/2) + +static inline bool +ip_set_timeout_test(unsigned long timeout) +{ + return timeout != IPSET_ELEM_UNSET + && (timeout == IPSET_ELEM_PERMANENT + || time_after(timeout, jiffies)); +} + +static inline bool +ip_set_timeout_expired(unsigned long timeout) +{ + return timeout != IPSET_ELEM_UNSET + && timeout != IPSET_ELEM_PERMANENT + && time_before(timeout, jiffies); +} + +static inline unsigned long +ip_set_timeout_set(u32 timeout) +{ + unsigned long t; + + if (!timeout) + return IPSET_ELEM_PERMANENT; + + t = timeout * HZ + jiffies; + if (t == IPSET_ELEM_UNSET || t == IPSET_ELEM_PERMANENT) + /* Bingo! */ + t++; + + return t; +} + +static inline u32 +ip_set_timeout_get(unsigned long timeout) +{ + return timeout == IPSET_ELEM_PERMANENT ? 0 : (timeout - jiffies)/HZ; +} + +#else + +/* Hash specific timeout constants and macros for the entries */ + +/* Hash entry is set with no timeout value */ +#define IPSET_ELEM_PERMANENT 0 + +static inline bool +ip_set_timeout_test(unsigned long timeout) +{ + return timeout == IPSET_ELEM_PERMANENT + || time_after(timeout, jiffies); +} + +static inline bool +ip_set_timeout_expired(unsigned long timeout) +{ + return timeout != IPSET_ELEM_PERMANENT + && time_before(timeout, jiffies); +} + +static inline unsigned long +ip_set_timeout_set(u32 timeout) +{ + unsigned long t; + + if (!timeout) + return IPSET_ELEM_PERMANENT; + + t = timeout * HZ + jiffies; + if (t == IPSET_ELEM_PERMANENT) + /* Bingo! :-) */ + t++; + + return t; +} + +static inline u32 +ip_set_timeout_get(unsigned long timeout) +{ + return timeout == IPSET_ELEM_PERMANENT ? 0 : (timeout - jiffies)/HZ; +} +#endif /* ! IP_SET_BITMAP_TIMEOUT */ + +#endif /* __KERNEL__ */ + +#endif /* _IP_SET_TIMEOUT_H */ diff --git a/kernel/include/linux/netfilter/xt_set.h b/kernel/include/linux/netfilter/xt_set.h index 949fa59..c6084df 100644 --- a/kernel/include/linux/netfilter/xt_set.h +++ b/kernel/include/linux/netfilter/xt_set.h @@ -1,7 +1,7 @@ #ifndef _XT_SET_H #define _XT_SET_H -#include +#include /* Revision 0 interface: backward compatible with netfilter/iptables */ -- cgit v1.2.3