diff options
| author | David S. Miller <davem@davemloft.net> | 2011-02-02 18:24:48 -0500 |
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2011-02-02 18:24:48 -0500 |
| commit | 8fe73503fae8cb8f00c80dd6444c1ddcd19257bd (patch) | |
| tree | 39cc6d38a628c445da7d52c006df6930a2c58411 /include/linux | |
| parent | 123b9731b14f49cd41c91ed2b6c31e515615347c (diff) | |
| parent | 9291747f118d6404e509747b85ff5f6dfec368d2 (diff) | |
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/kaber/nf-next-2.6
Diffstat (limited to 'include/linux')
| -rw-r--r-- | include/linux/netfilter/Kbuild | 4 | ||||
| -rw-r--r-- | include/linux/netfilter/ipset/Kbuild | 4 | ||||
| -rw-r--r-- | include/linux/netfilter/ipset/ip_set.h | 452 | ||||
| -rw-r--r-- | include/linux/netfilter/ipset/ip_set_ahash.h | 1074 | ||||
| -rw-r--r-- | include/linux/netfilter/ipset/ip_set_bitmap.h | 31 | ||||
| -rw-r--r-- | include/linux/netfilter/ipset/ip_set_getport.h | 21 | ||||
| -rw-r--r-- | include/linux/netfilter/ipset/ip_set_hash.h | 26 | ||||
| -rw-r--r-- | include/linux/netfilter/ipset/ip_set_list.h | 27 | ||||
| -rw-r--r-- | include/linux/netfilter/ipset/ip_set_timeout.h | 127 | ||||
| -rw-r--r-- | include/linux/netfilter/ipset/pfxlen.h | 35 | ||||
| -rw-r--r-- | include/linux/netfilter/nfnetlink.h | 3 | ||||
| -rw-r--r-- | include/linux/netfilter/xt_devgroup.h | 21 | ||||
| -rw-r--r-- | include/linux/netfilter/xt_set.h | 56 |
13 files changed, 1880 insertions, 1 deletions
diff --git a/include/linux/netfilter/Kbuild b/include/linux/netfilter/Kbuild index 89c0d1e20d72..15e83bf3dd58 100644 --- a/include/linux/netfilter/Kbuild +++ b/include/linux/netfilter/Kbuild | |||
| @@ -1,3 +1,5 @@ | |||
| 1 | header-y += ipset/ | ||
| 2 | |||
| 1 | header-y += nf_conntrack_common.h | 3 | header-y += nf_conntrack_common.h |
| 2 | header-y += nf_conntrack_ftp.h | 4 | header-y += nf_conntrack_ftp.h |
| 3 | header-y += nf_conntrack_sctp.h | 5 | header-y += nf_conntrack_sctp.h |
| @@ -35,6 +37,7 @@ header-y += xt_connmark.h | |||
| 35 | header-y += xt_conntrack.h | 37 | header-y += xt_conntrack.h |
| 36 | header-y += xt_cpu.h | 38 | header-y += xt_cpu.h |
| 37 | header-y += xt_dccp.h | 39 | header-y += xt_dccp.h |
| 40 | header-y += xt_devgroup.h | ||
| 38 | header-y += xt_dscp.h | 41 | header-y += xt_dscp.h |
| 39 | header-y += xt_esp.h | 42 | header-y += xt_esp.h |
| 40 | header-y += xt_hashlimit.h | 43 | header-y += xt_hashlimit.h |
| @@ -55,6 +58,7 @@ header-y += xt_quota.h | |||
| 55 | header-y += xt_rateest.h | 58 | header-y += xt_rateest.h |
| 56 | header-y += xt_realm.h | 59 | header-y += xt_realm.h |
| 57 | header-y += xt_recent.h | 60 | header-y += xt_recent.h |
| 61 | header-y += xt_set.h | ||
| 58 | header-y += xt_sctp.h | 62 | header-y += xt_sctp.h |
| 59 | header-y += xt_socket.h | 63 | header-y += xt_socket.h |
| 60 | header-y += xt_state.h | 64 | header-y += xt_state.h |
diff --git a/include/linux/netfilter/ipset/Kbuild b/include/linux/netfilter/ipset/Kbuild new file mode 100644 index 000000000000..601fe71d34d5 --- /dev/null +++ b/include/linux/netfilter/ipset/Kbuild | |||
| @@ -0,0 +1,4 @@ | |||
| 1 | header-y += ip_set.h | ||
| 2 | header-y += ip_set_bitmap.h | ||
| 3 | header-y += ip_set_hash.h | ||
| 4 | header-y += ip_set_list.h | ||
diff --git a/include/linux/netfilter/ipset/ip_set.h b/include/linux/netfilter/ipset/ip_set.h new file mode 100644 index 000000000000..ec333d83f3b4 --- /dev/null +++ b/include/linux/netfilter/ipset/ip_set.h | |||
| @@ -0,0 +1,452 @@ | |||
| 1 | #ifndef _IP_SET_H | ||
| 2 | #define _IP_SET_H | ||
| 3 | |||
| 4 | /* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu> | ||
| 5 | * Patrick Schaaf <bof@bof.de> | ||
| 6 | * Martin Josefsson <gandalf@wlug.westbo.se> | ||
| 7 | * Copyright (C) 2003-2011 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu> | ||
| 8 | * | ||
| 9 | * This program is free software; you can redistribute it and/or modify | ||
| 10 | * it under the terms of the GNU General Public License version 2 as | ||
| 11 | * published by the Free Software Foundation. | ||
| 12 | */ | ||
| 13 | |||
| 14 | /* The protocol version */ | ||
| 15 | #define IPSET_PROTOCOL 6 | ||
| 16 | |||
| 17 | /* The max length of strings including NUL: set and type identifiers */ | ||
| 18 | #define IPSET_MAXNAMELEN 32 | ||
| 19 | |||
| 20 | /* Message types and commands */ | ||
| 21 | enum ipset_cmd { | ||
| 22 | IPSET_CMD_NONE, | ||
| 23 | IPSET_CMD_PROTOCOL, /* 1: Return protocol version */ | ||
| 24 | IPSET_CMD_CREATE, /* 2: Create a new (empty) set */ | ||
| 25 | IPSET_CMD_DESTROY, /* 3: Destroy a (empty) set */ | ||
| 26 | IPSET_CMD_FLUSH, /* 4: Remove all elements from a set */ | ||
| 27 | IPSET_CMD_RENAME, /* 5: Rename a set */ | ||
| 28 | IPSET_CMD_SWAP, /* 6: Swap two sets */ | ||
| 29 | IPSET_CMD_LIST, /* 7: List sets */ | ||
| 30 | IPSET_CMD_SAVE, /* 8: Save sets */ | ||
| 31 | IPSET_CMD_ADD, /* 9: Add an element to a set */ | ||
| 32 | IPSET_CMD_DEL, /* 10: Delete an element from a set */ | ||
| 33 | IPSET_CMD_TEST, /* 11: Test an element in a set */ | ||
| 34 | IPSET_CMD_HEADER, /* 12: Get set header data only */ | ||
| 35 | IPSET_CMD_TYPE, /* 13: Get set type */ | ||
| 36 | IPSET_MSG_MAX, /* Netlink message commands */ | ||
| 37 | |||
| 38 | /* Commands in userspace: */ | ||
| 39 | IPSET_CMD_RESTORE = IPSET_MSG_MAX, /* 14: Enter restore mode */ | ||
| 40 | IPSET_CMD_HELP, /* 15: Get help */ | ||
| 41 | IPSET_CMD_VERSION, /* 16: Get program version */ | ||
| 42 | IPSET_CMD_QUIT, /* 17: Quit from interactive mode */ | ||
| 43 | |||
| 44 | IPSET_CMD_MAX, | ||
| 45 | |||
| 46 | IPSET_CMD_COMMIT = IPSET_CMD_MAX, /* 18: Commit buffered commands */ | ||
| 47 | }; | ||
| 48 | |||
| 49 | /* Attributes at command level */ | ||
| 50 | enum { | ||
| 51 | IPSET_ATTR_UNSPEC, | ||
| 52 | IPSET_ATTR_PROTOCOL, /* 1: Protocol version */ | ||
| 53 | IPSET_ATTR_SETNAME, /* 2: Name of the set */ | ||
| 54 | IPSET_ATTR_TYPENAME, /* 3: Typename */ | ||
| 55 | IPSET_ATTR_SETNAME2 = IPSET_ATTR_TYPENAME, /* Setname at rename/swap */ | ||
| 56 | IPSET_ATTR_REVISION, /* 4: Settype revision */ | ||
| 57 | IPSET_ATTR_FAMILY, /* 5: Settype family */ | ||
| 58 | IPSET_ATTR_FLAGS, /* 6: Flags at command level */ | ||
| 59 | IPSET_ATTR_DATA, /* 7: Nested attributes */ | ||
| 60 | IPSET_ATTR_ADT, /* 8: Multiple data containers */ | ||
| 61 | IPSET_ATTR_LINENO, /* 9: Restore lineno */ | ||
| 62 | IPSET_ATTR_PROTOCOL_MIN, /* 10: Minimal supported version number */ | ||
| 63 | IPSET_ATTR_REVISION_MIN = IPSET_ATTR_PROTOCOL_MIN, /* type rev min */ | ||
| 64 | __IPSET_ATTR_CMD_MAX, | ||
| 65 | }; | ||
| 66 | #define IPSET_ATTR_CMD_MAX (__IPSET_ATTR_CMD_MAX - 1) | ||
| 67 | |||
| 68 | /* CADT specific attributes */ | ||
| 69 | enum { | ||
| 70 | IPSET_ATTR_IP = IPSET_ATTR_UNSPEC + 1, | ||
| 71 | IPSET_ATTR_IP_FROM = IPSET_ATTR_IP, | ||
| 72 | IPSET_ATTR_IP_TO, /* 2 */ | ||
| 73 | IPSET_ATTR_CIDR, /* 3 */ | ||
| 74 | IPSET_ATTR_PORT, /* 4 */ | ||
| 75 | IPSET_ATTR_PORT_FROM = IPSET_ATTR_PORT, | ||
| 76 | IPSET_ATTR_PORT_TO, /* 5 */ | ||
| 77 | IPSET_ATTR_TIMEOUT, /* 6 */ | ||
| 78 | IPSET_ATTR_PROTO, /* 7 */ | ||
| 79 | IPSET_ATTR_CADT_FLAGS, /* 8 */ | ||
| 80 | IPSET_ATTR_CADT_LINENO = IPSET_ATTR_LINENO, /* 9 */ | ||
| 81 | /* Reserve empty slots */ | ||
| 82 | IPSET_ATTR_CADT_MAX = 16, | ||
| 83 | /* Create-only specific attributes */ | ||
| 84 | IPSET_ATTR_GC, | ||
| 85 | IPSET_ATTR_HASHSIZE, | ||
| 86 | IPSET_ATTR_MAXELEM, | ||
| 87 | IPSET_ATTR_NETMASK, | ||
| 88 | IPSET_ATTR_PROBES, | ||
| 89 | IPSET_ATTR_RESIZE, | ||
| 90 | IPSET_ATTR_SIZE, | ||
| 91 | /* Kernel-only */ | ||
| 92 | IPSET_ATTR_ELEMENTS, | ||
| 93 | IPSET_ATTR_REFERENCES, | ||
| 94 | IPSET_ATTR_MEMSIZE, | ||
| 95 | |||
| 96 | __IPSET_ATTR_CREATE_MAX, | ||
| 97 | }; | ||
| 98 | #define IPSET_ATTR_CREATE_MAX (__IPSET_ATTR_CREATE_MAX - 1) | ||
| 99 | |||
| 100 | /* ADT specific attributes */ | ||
| 101 | enum { | ||
| 102 | IPSET_ATTR_ETHER = IPSET_ATTR_CADT_MAX + 1, | ||
| 103 | IPSET_ATTR_NAME, | ||
| 104 | IPSET_ATTR_NAMEREF, | ||
| 105 | IPSET_ATTR_IP2, | ||
| 106 | IPSET_ATTR_CIDR2, | ||
| 107 | __IPSET_ATTR_ADT_MAX, | ||
| 108 | }; | ||
| 109 | #define IPSET_ATTR_ADT_MAX (__IPSET_ATTR_ADT_MAX - 1) | ||
| 110 | |||
| 111 | /* IP specific attributes */ | ||
| 112 | enum { | ||
| 113 | IPSET_ATTR_IPADDR_IPV4 = IPSET_ATTR_UNSPEC + 1, | ||
| 114 | IPSET_ATTR_IPADDR_IPV6, | ||
| 115 | __IPSET_ATTR_IPADDR_MAX, | ||
| 116 | }; | ||
| 117 | #define IPSET_ATTR_IPADDR_MAX (__IPSET_ATTR_IPADDR_MAX - 1) | ||
| 118 | |||
| 119 | /* Error codes */ | ||
| 120 | enum ipset_errno { | ||
| 121 | IPSET_ERR_PRIVATE = 4096, | ||
| 122 | IPSET_ERR_PROTOCOL, | ||
| 123 | IPSET_ERR_FIND_TYPE, | ||
| 124 | IPSET_ERR_MAX_SETS, | ||
| 125 | IPSET_ERR_BUSY, | ||
| 126 | IPSET_ERR_EXIST_SETNAME2, | ||
| 127 | IPSET_ERR_TYPE_MISMATCH, | ||
| 128 | IPSET_ERR_EXIST, | ||
| 129 | IPSET_ERR_INVALID_CIDR, | ||
| 130 | IPSET_ERR_INVALID_NETMASK, | ||
| 131 | IPSET_ERR_INVALID_FAMILY, | ||
| 132 | IPSET_ERR_TIMEOUT, | ||
| 133 | IPSET_ERR_REFERENCED, | ||
| 134 | IPSET_ERR_IPADDR_IPV4, | ||
| 135 | IPSET_ERR_IPADDR_IPV6, | ||
| 136 | |||
| 137 | /* Type specific error codes */ | ||
| 138 | IPSET_ERR_TYPE_SPECIFIC = 4352, | ||
| 139 | }; | ||
| 140 | |||
| 141 | /* Flags at command level */ | ||
| 142 | enum ipset_cmd_flags { | ||
| 143 | IPSET_FLAG_BIT_EXIST = 0, | ||
| 144 | IPSET_FLAG_EXIST = (1 << IPSET_FLAG_BIT_EXIST), | ||
| 145 | }; | ||
| 146 | |||
| 147 | /* Flags at CADT attribute level */ | ||
| 148 | enum ipset_cadt_flags { | ||
| 149 | IPSET_FLAG_BIT_BEFORE = 0, | ||
| 150 | IPSET_FLAG_BEFORE = (1 << IPSET_FLAG_BIT_BEFORE), | ||
| 151 | }; | ||
| 152 | |||
| 153 | /* Commands with settype-specific attributes */ | ||
| 154 | enum ipset_adt { | ||
| 155 | IPSET_ADD, | ||
| 156 | IPSET_DEL, | ||
| 157 | IPSET_TEST, | ||
| 158 | IPSET_ADT_MAX, | ||
| 159 | IPSET_CREATE = IPSET_ADT_MAX, | ||
| 160 | IPSET_CADT_MAX, | ||
| 161 | }; | ||
| 162 | |||
| 163 | #ifdef __KERNEL__ | ||
| 164 | #include <linux/ip.h> | ||
| 165 | #include <linux/ipv6.h> | ||
| 166 | #include <linux/netlink.h> | ||
| 167 | #include <linux/netfilter.h> | ||
| 168 | #include <linux/vmalloc.h> | ||
| 169 | #include <net/netlink.h> | ||
| 170 | |||
| 171 | /* Sets are identified by an index in kernel space. Tweak with ip_set_id_t | ||
| 172 | * and IPSET_INVALID_ID if you want to increase the max number of sets. | ||
| 173 | */ | ||
| 174 | typedef u16 ip_set_id_t; | ||
| 175 | |||
| 176 | #define IPSET_INVALID_ID 65535 | ||
| 177 | |||
| 178 | enum ip_set_dim { | ||
| 179 | IPSET_DIM_ZERO = 0, | ||
| 180 | IPSET_DIM_ONE, | ||
| 181 | IPSET_DIM_TWO, | ||
| 182 | IPSET_DIM_THREE, | ||
| 183 | /* Max dimension in elements. | ||
| 184 | * If changed, new revision of iptables match/target is required. | ||
| 185 | */ | ||
| 186 | IPSET_DIM_MAX = 6, | ||
| 187 | }; | ||
| 188 | |||
| 189 | /* Option flags for kernel operations */ | ||
| 190 | enum ip_set_kopt { | ||
| 191 | IPSET_INV_MATCH = (1 << IPSET_DIM_ZERO), | ||
| 192 | IPSET_DIM_ONE_SRC = (1 << IPSET_DIM_ONE), | ||
| 193 | IPSET_DIM_TWO_SRC = (1 << IPSET_DIM_TWO), | ||
| 194 | IPSET_DIM_THREE_SRC = (1 << IPSET_DIM_THREE), | ||
| 195 | }; | ||
| 196 | |||
| 197 | /* Set features */ | ||
| 198 | enum ip_set_feature { | ||
| 199 | IPSET_TYPE_IP_FLAG = 0, | ||
| 200 | IPSET_TYPE_IP = (1 << IPSET_TYPE_IP_FLAG), | ||
| 201 | IPSET_TYPE_PORT_FLAG = 1, | ||
| 202 | IPSET_TYPE_PORT = (1 << IPSET_TYPE_PORT_FLAG), | ||
| 203 | IPSET_TYPE_MAC_FLAG = 2, | ||
| 204 | IPSET_TYPE_MAC = (1 << IPSET_TYPE_MAC_FLAG), | ||
| 205 | IPSET_TYPE_IP2_FLAG = 3, | ||
| 206 | IPSET_TYPE_IP2 = (1 << IPSET_TYPE_IP2_FLAG), | ||
| 207 | IPSET_TYPE_NAME_FLAG = 4, | ||
| 208 | IPSET_TYPE_NAME = (1 << IPSET_TYPE_NAME_FLAG), | ||
| 209 | /* Strictly speaking not a feature, but a flag for dumping: | ||
| 210 | * this settype must be dumped last */ | ||
| 211 | IPSET_DUMP_LAST_FLAG = 7, | ||
| 212 | IPSET_DUMP_LAST = (1 << IPSET_DUMP_LAST_FLAG), | ||
| 213 | }; | ||
| 214 | |||
| 215 | struct ip_set; | ||
| 216 | |||
| 217 | typedef int (*ipset_adtfn)(struct ip_set *set, void *value, u32 timeout); | ||
| 218 | |||
| 219 | /* Set type, variant-specific part */ | ||
| 220 | struct ip_set_type_variant { | ||
| 221 | /* Kernelspace: test/add/del entries | ||
| 222 | * returns negative error code, | ||
| 223 | * zero for no match/success to add/delete | ||
| 224 | * positive for matching element */ | ||
| 225 | int (*kadt)(struct ip_set *set, const struct sk_buff * skb, | ||
| 226 | enum ipset_adt adt, u8 pf, u8 dim, u8 flags); | ||
| 227 | |||
| 228 | /* Userspace: test/add/del entries | ||
| 229 | * returns negative error code, | ||
| 230 | * zero for no match/success to add/delete | ||
| 231 | * positive for matching element */ | ||
| 232 | int (*uadt)(struct ip_set *set, struct nlattr *tb[], | ||
| 233 | enum ipset_adt adt, u32 *lineno, u32 flags); | ||
| 234 | |||
| 235 | /* Low level add/del/test functions */ | ||
| 236 | ipset_adtfn adt[IPSET_ADT_MAX]; | ||
| 237 | |||
| 238 | /* When adding entries and set is full, try to resize the set */ | ||
| 239 | int (*resize)(struct ip_set *set, bool retried); | ||
| 240 | /* Destroy the set */ | ||
| 241 | void (*destroy)(struct ip_set *set); | ||
| 242 | /* Flush the elements */ | ||
| 243 | void (*flush)(struct ip_set *set); | ||
| 244 | /* Expire entries before listing */ | ||
| 245 | void (*expire)(struct ip_set *set); | ||
| 246 | /* List set header data */ | ||
| 247 | int (*head)(struct ip_set *set, struct sk_buff *skb); | ||
| 248 | /* List elements */ | ||
| 249 | int (*list)(const struct ip_set *set, struct sk_buff *skb, | ||
| 250 | struct netlink_callback *cb); | ||
| 251 | |||
| 252 | /* Return true if "b" set is the same as "a" | ||
| 253 | * according to the create set parameters */ | ||
| 254 | bool (*same_set)(const struct ip_set *a, const struct ip_set *b); | ||
| 255 | }; | ||
| 256 | |||
| 257 | /* The core set type structure */ | ||
| 258 | struct ip_set_type { | ||
| 259 | struct list_head list; | ||
| 260 | |||
| 261 | /* Typename */ | ||
| 262 | char name[IPSET_MAXNAMELEN]; | ||
| 263 | /* Protocol version */ | ||
| 264 | u8 protocol; | ||
| 265 | /* Set features to control swapping */ | ||
| 266 | u8 features; | ||
| 267 | /* Set type dimension */ | ||
| 268 | u8 dimension; | ||
| 269 | /* Supported family: may be AF_UNSPEC for both AF_INET/AF_INET6 */ | ||
| 270 | u8 family; | ||
| 271 | /* Type revision */ | ||
| 272 | u8 revision; | ||
| 273 | |||
| 274 | /* Create set */ | ||
| 275 | int (*create)(struct ip_set *set, struct nlattr *tb[], u32 flags); | ||
| 276 | |||
| 277 | /* Attribute policies */ | ||
| 278 | const struct nla_policy create_policy[IPSET_ATTR_CREATE_MAX + 1]; | ||
| 279 | const struct nla_policy adt_policy[IPSET_ATTR_ADT_MAX + 1]; | ||
| 280 | |||
| 281 | /* Set this to THIS_MODULE if you are a module, otherwise NULL */ | ||
| 282 | struct module *me; | ||
| 283 | }; | ||
| 284 | |||
| 285 | /* register and unregister set type */ | ||
| 286 | extern int ip_set_type_register(struct ip_set_type *set_type); | ||
| 287 | extern void ip_set_type_unregister(struct ip_set_type *set_type); | ||
| 288 | |||
| 289 | /* A generic IP set */ | ||
| 290 | struct ip_set { | ||
| 291 | /* The name of the set */ | ||
| 292 | char name[IPSET_MAXNAMELEN]; | ||
| 293 | /* Lock protecting the set data */ | ||
| 294 | rwlock_t lock; | ||
| 295 | /* References to the set */ | ||
| 296 | atomic_t ref; | ||
| 297 | /* The core set type */ | ||
| 298 | struct ip_set_type *type; | ||
| 299 | /* The type variant doing the real job */ | ||
| 300 | const struct ip_set_type_variant *variant; | ||
| 301 | /* The actual INET family of the set */ | ||
| 302 | u8 family; | ||
| 303 | /* The type specific data */ | ||
| 304 | void *data; | ||
| 305 | }; | ||
| 306 | |||
| 307 | /* register and unregister set references */ | ||
| 308 | extern ip_set_id_t ip_set_get_byname(const char *name, struct ip_set **set); | ||
| 309 | extern void ip_set_put_byindex(ip_set_id_t index); | ||
| 310 | extern const char * ip_set_name_byindex(ip_set_id_t index); | ||
| 311 | extern ip_set_id_t ip_set_nfnl_get(const char *name); | ||
| 312 | extern ip_set_id_t ip_set_nfnl_get_byindex(ip_set_id_t index); | ||
| 313 | extern void ip_set_nfnl_put(ip_set_id_t index); | ||
| 314 | |||
| 315 | /* API for iptables set match, and SET target */ | ||
| 316 | extern int ip_set_add(ip_set_id_t id, const struct sk_buff *skb, | ||
| 317 | u8 family, u8 dim, u8 flags); | ||
| 318 | extern int ip_set_del(ip_set_id_t id, const struct sk_buff *skb, | ||
| 319 | u8 family, u8 dim, u8 flags); | ||
| 320 | extern int ip_set_test(ip_set_id_t id, const struct sk_buff *skb, | ||
| 321 | u8 family, u8 dim, u8 flags); | ||
| 322 | |||
| 323 | /* Utility functions */ | ||
| 324 | extern void * ip_set_alloc(size_t size); | ||
| 325 | extern void ip_set_free(void *members); | ||
| 326 | extern int ip_set_get_ipaddr4(struct nlattr *nla, __be32 *ipaddr); | ||
| 327 | extern int ip_set_get_ipaddr6(struct nlattr *nla, union nf_inet_addr *ipaddr); | ||
| 328 | |||
| 329 | static inline int | ||
| 330 | ip_set_get_hostipaddr4(struct nlattr *nla, u32 *ipaddr) | ||
| 331 | { | ||
| 332 | __be32 ip; | ||
| 333 | int ret = ip_set_get_ipaddr4(nla, &ip); | ||
| 334 | |||
| 335 | if (ret) | ||
| 336 | return ret; | ||
| 337 | *ipaddr = ntohl(ip); | ||
| 338 | return 0; | ||
| 339 | } | ||
| 340 | |||
| 341 | /* Ignore IPSET_ERR_EXIST errors if asked to do so? */ | ||
| 342 | static inline bool | ||
| 343 | ip_set_eexist(int ret, u32 flags) | ||
| 344 | { | ||
| 345 | return ret == -IPSET_ERR_EXIST && (flags & IPSET_FLAG_EXIST); | ||
| 346 | } | ||
| 347 | |||
| 348 | /* Check the NLA_F_NET_BYTEORDER flag */ | ||
| 349 | static inline bool | ||
| 350 | ip_set_attr_netorder(struct nlattr *tb[], int type) | ||
| 351 | { | ||
| 352 | return tb[type] && (tb[type]->nla_type & NLA_F_NET_BYTEORDER); | ||
| 353 | } | ||
| 354 | |||
| 355 | static inline bool | ||
| 356 | ip_set_optattr_netorder(struct nlattr *tb[], int type) | ||
| 357 | { | ||
| 358 | return !tb[type] || (tb[type]->nla_type & NLA_F_NET_BYTEORDER); | ||
| 359 | } | ||
| 360 | |||
| 361 | /* Useful converters */ | ||
| 362 | static inline u32 | ||
| 363 | ip_set_get_h32(const struct nlattr *attr) | ||
| 364 | { | ||
| 365 | return ntohl(nla_get_be32(attr)); | ||
| 366 | } | ||
| 367 | |||
| 368 | static inline u16 | ||
| 369 | ip_set_get_h16(const struct nlattr *attr) | ||
| 370 | { | ||
| 371 | return ntohs(nla_get_be16(attr)); | ||
| 372 | } | ||
| 373 | |||
| 374 | #define ipset_nest_start(skb, attr) nla_nest_start(skb, attr | NLA_F_NESTED) | ||
| 375 | #define ipset_nest_end(skb, start) nla_nest_end(skb, start) | ||
| 376 | |||
| 377 | #define NLA_PUT_IPADDR4(skb, type, ipaddr) \ | ||
| 378 | do { \ | ||
| 379 | struct nlattr *__nested = ipset_nest_start(skb, type); \ | ||
| 380 | \ | ||
| 381 | if (!__nested) \ | ||
| 382 | goto nla_put_failure; \ | ||
| 383 | NLA_PUT_NET32(skb, IPSET_ATTR_IPADDR_IPV4, ipaddr); \ | ||
| 384 | ipset_nest_end(skb, __nested); \ | ||
| 385 | } while (0) | ||
| 386 | |||
| 387 | #define NLA_PUT_IPADDR6(skb, type, ipaddrptr) \ | ||
| 388 | do { \ | ||
| 389 | struct nlattr *__nested = ipset_nest_start(skb, type); \ | ||
| 390 | \ | ||
| 391 | if (!__nested) \ | ||
| 392 | goto nla_put_failure; \ | ||
| 393 | NLA_PUT(skb, IPSET_ATTR_IPADDR_IPV6, \ | ||
| 394 | sizeof(struct in6_addr), ipaddrptr); \ | ||
| 395 | ipset_nest_end(skb, __nested); \ | ||
| 396 | } while (0) | ||
| 397 | |||
| 398 | /* Get address from skbuff */ | ||
| 399 | static inline __be32 | ||
| 400 | ip4addr(const struct sk_buff *skb, bool src) | ||
| 401 | { | ||
| 402 | return src ? ip_hdr(skb)->saddr : ip_hdr(skb)->daddr; | ||
| 403 | } | ||
| 404 | |||
| 405 | static inline void | ||
| 406 | ip4addrptr(const struct sk_buff *skb, bool src, __be32 *addr) | ||
| 407 | { | ||
| 408 | *addr = src ? ip_hdr(skb)->saddr : ip_hdr(skb)->daddr; | ||
| 409 | } | ||
| 410 | |||
| 411 | static inline void | ||
| 412 | ip6addrptr(const struct sk_buff *skb, bool src, struct in6_addr *addr) | ||
| 413 | { | ||
| 414 | memcpy(addr, src ? &ipv6_hdr(skb)->saddr : &ipv6_hdr(skb)->daddr, | ||
| 415 | sizeof(*addr)); | ||
| 416 | } | ||
| 417 | |||
| 418 | /* Calculate the bytes required to store the inclusive range of a-b */ | ||
| 419 | static inline int | ||
| 420 | bitmap_bytes(u32 a, u32 b) | ||
| 421 | { | ||
| 422 | return 4 * ((((b - a + 8) / 8) + 3) / 4); | ||
| 423 | } | ||
| 424 | |||
| 425 | /* Interface to iptables/ip6tables */ | ||
| 426 | |||
| 427 | #define SO_IP_SET 83 | ||
| 428 | |||
| 429 | union ip_set_name_index { | ||
| 430 | char name[IPSET_MAXNAMELEN]; | ||
| 431 | ip_set_id_t index; | ||
| 432 | }; | ||
| 433 | |||
| 434 | #define IP_SET_OP_GET_BYNAME 0x00000006 /* Get set index by name */ | ||
| 435 | struct ip_set_req_get_set { | ||
| 436 | unsigned op; | ||
| 437 | unsigned version; | ||
| 438 | union ip_set_name_index set; | ||
| 439 | }; | ||
| 440 | |||
| 441 | #define IP_SET_OP_GET_BYINDEX 0x00000007 /* Get set name by index */ | ||
| 442 | /* Uses ip_set_req_get_set */ | ||
| 443 | |||
| 444 | #define IP_SET_OP_VERSION 0x00000100 /* Ask kernel version */ | ||
| 445 | struct ip_set_req_version { | ||
| 446 | unsigned op; | ||
| 447 | unsigned version; | ||
| 448 | }; | ||
| 449 | |||
| 450 | #endif /* __KERNEL__ */ | ||
| 451 | |||
| 452 | #endif /*_IP_SET_H */ | ||
diff --git a/include/linux/netfilter/ipset/ip_set_ahash.h b/include/linux/netfilter/ipset/ip_set_ahash.h new file mode 100644 index 000000000000..ec9d9bea1e37 --- /dev/null +++ b/include/linux/netfilter/ipset/ip_set_ahash.h | |||
| @@ -0,0 +1,1074 @@ | |||
| 1 | #ifndef _IP_SET_AHASH_H | ||
| 2 | #define _IP_SET_AHASH_H | ||
| 3 | |||
| 4 | #include <linux/rcupdate.h> | ||
| 5 | #include <linux/jhash.h> | ||
| 6 | #include <linux/netfilter/ipset/ip_set_timeout.h> | ||
| 7 | |||
| 8 | /* Hashing which uses arrays to resolve clashing. The hash table is resized | ||
| 9 | * (doubled) when searching becomes too long. | ||
| 10 | * Internally jhash is used with the assumption that the size of the | ||
| 11 | * stored data is a multiple of sizeof(u32). If storage supports timeout, | ||
| 12 | * the timeout field must be the last one in the data structure - that field | ||
| 13 | * is ignored when computing the hash key. | ||
| 14 | * | ||
| 15 | * Readers and resizing | ||
| 16 | * | ||
| 17 | * Resizing can be triggered by userspace command only, and those | ||
| 18 | * are serialized by the nfnl mutex. During resizing the set is | ||
| 19 | * read-locked, so the only possible concurrent operations are | ||
| 20 | * the kernel side readers. Those must be protected by proper RCU locking. | ||
| 21 | */ | ||
| 22 | |||
| 23 | /* Number of elements to store in an initial array block */ | ||
| 24 | #define AHASH_INIT_SIZE 4 | ||
| 25 | /* Max number of elements to store in an array block */ | ||
| 26 | #define AHASH_MAX_SIZE (3*4) | ||
| 27 | |||
| 28 | /* A hash bucket */ | ||
| 29 | struct hbucket { | ||
| 30 | void *value; /* the array of the values */ | ||
| 31 | u8 size; /* size of the array */ | ||
| 32 | u8 pos; /* position of the first free entry */ | ||
| 33 | }; | ||
| 34 | |||
| 35 | /* The hash table: the table size stored here in order to make resizing easy */ | ||
| 36 | struct htable { | ||
| 37 | u8 htable_bits; /* size of hash table == 2^htable_bits */ | ||
| 38 | struct hbucket bucket[0]; /* hashtable buckets */ | ||
| 39 | }; | ||
| 40 | |||
| 41 | #define hbucket(h, i) &((h)->bucket[i]) | ||
| 42 | |||
| 43 | /* Book-keeping of the prefixes added to the set */ | ||
| 44 | struct ip_set_hash_nets { | ||
| 45 | u8 cidr; /* the different cidr values in the set */ | ||
| 46 | u32 nets; /* number of elements per cidr */ | ||
| 47 | }; | ||
| 48 | |||
| 49 | /* The generic ip_set hash structure */ | ||
| 50 | struct ip_set_hash { | ||
| 51 | struct htable *table; /* the hash table */ | ||
| 52 | u32 maxelem; /* max elements in the hash */ | ||
| 53 | u32 elements; /* current element (vs timeout) */ | ||
| 54 | u32 initval; /* random jhash init value */ | ||
| 55 | u32 timeout; /* timeout value, if enabled */ | ||
| 56 | struct timer_list gc; /* garbage collection when timeout enabled */ | ||
| 57 | #ifdef IP_SET_HASH_WITH_NETMASK | ||
| 58 | u8 netmask; /* netmask value for subnets to store */ | ||
| 59 | #endif | ||
| 60 | #ifdef IP_SET_HASH_WITH_NETS | ||
| 61 | struct ip_set_hash_nets nets[0]; /* book-keeping of prefixes */ | ||
| 62 | #endif | ||
| 63 | }; | ||
| 64 | |||
| 65 | /* Compute htable_bits from the user input parameter hashsize */ | ||
| 66 | static u8 | ||
| 67 | htable_bits(u32 hashsize) | ||
| 68 | { | ||
| 69 | /* Assume that hashsize == 2^htable_bits */ | ||
| 70 | u8 bits = fls(hashsize - 1); | ||
| 71 | if (jhash_size(bits) != hashsize) | ||
| 72 | /* Round up to the first 2^n value */ | ||
| 73 | bits = fls(hashsize); | ||
| 74 | |||
| 75 | return bits; | ||
| 76 | } | ||
| 77 | |||
| 78 | #ifdef IP_SET_HASH_WITH_NETS | ||
| 79 | |||
| 80 | #define SET_HOST_MASK(family) (family == AF_INET ? 32 : 128) | ||
| 81 | |||
| 82 | /* Network cidr size book keeping when the hash stores different | ||
| 83 | * sized networks */ | ||
| 84 | static void | ||
| 85 | add_cidr(struct ip_set_hash *h, u8 cidr, u8 host_mask) | ||
| 86 | { | ||
| 87 | u8 i; | ||
| 88 | |||
| 89 | ++h->nets[cidr-1].nets; | ||
| 90 | |||
| 91 | pr_debug("add_cidr added %u: %u\n", cidr, h->nets[cidr-1].nets); | ||
| 92 | |||
| 93 | if (h->nets[cidr-1].nets > 1) | ||
| 94 | return; | ||
| 95 | |||
| 96 | /* New cidr size */ | ||
| 97 | for (i = 0; i < host_mask && h->nets[i].cidr; i++) { | ||
| 98 | /* Add in increasing prefix order, so larger cidr first */ | ||
| 99 | if (h->nets[i].cidr < cidr) | ||
| 100 | swap(h->nets[i].cidr, cidr); | ||
| 101 | } | ||
| 102 | if (i < host_mask) | ||
| 103 | h->nets[i].cidr = cidr; | ||
| 104 | } | ||
| 105 | |||
| 106 | static void | ||
| 107 | del_cidr(struct ip_set_hash *h, u8 cidr, u8 host_mask) | ||
| 108 | { | ||
| 109 | u8 i; | ||
| 110 | |||
| 111 | --h->nets[cidr-1].nets; | ||
| 112 | |||
| 113 | pr_debug("del_cidr deleted %u: %u\n", cidr, h->nets[cidr-1].nets); | ||
| 114 | |||
| 115 | if (h->nets[cidr-1].nets != 0) | ||
| 116 | return; | ||
| 117 | |||
| 118 | /* All entries with this cidr size deleted, so cleanup h->cidr[] */ | ||
| 119 | for (i = 0; i < host_mask - 1 && h->nets[i].cidr; i++) { | ||
| 120 | if (h->nets[i].cidr == cidr) | ||
| 121 | h->nets[i].cidr = cidr = h->nets[i+1].cidr; | ||
| 122 | } | ||
| 123 | h->nets[i - 1].cidr = 0; | ||
| 124 | } | ||
| 125 | #endif | ||
| 126 | |||
| 127 | /* Destroy the hashtable part of the set */ | ||
| 128 | static void | ||
| 129 | ahash_destroy(struct htable *t) | ||
| 130 | { | ||
| 131 | struct hbucket *n; | ||
| 132 | u32 i; | ||
| 133 | |||
| 134 | for (i = 0; i < jhash_size(t->htable_bits); i++) { | ||
| 135 | n = hbucket(t, i); | ||
| 136 | if (n->size) | ||
| 137 | /* FIXME: use slab cache */ | ||
| 138 | kfree(n->value); | ||
| 139 | } | ||
| 140 | |||
| 141 | ip_set_free(t); | ||
| 142 | } | ||
| 143 | |||
| 144 | /* Calculate the actual memory size of the set data */ | ||
| 145 | static size_t | ||
| 146 | ahash_memsize(const struct ip_set_hash *h, size_t dsize, u8 host_mask) | ||
| 147 | { | ||
| 148 | u32 i; | ||
| 149 | struct htable *t = h->table; | ||
| 150 | size_t memsize = sizeof(*h) | ||
| 151 | + sizeof(*t) | ||
| 152 | #ifdef IP_SET_HASH_WITH_NETS | ||
| 153 | + sizeof(struct ip_set_hash_nets) * host_mask | ||
| 154 | #endif | ||
| 155 | + jhash_size(t->htable_bits) * sizeof(struct hbucket); | ||
| 156 | |||
| 157 | for (i = 0; i < jhash_size(t->htable_bits); i++) | ||
| 158 | memsize += t->bucket[i].size * dsize; | ||
| 159 | |||
| 160 | return memsize; | ||
| 161 | } | ||
| 162 | |||
| 163 | /* Flush a hash type of set: destroy all elements */ | ||
| 164 | static void | ||
| 165 | ip_set_hash_flush(struct ip_set *set) | ||
| 166 | { | ||
| 167 | struct ip_set_hash *h = set->data; | ||
| 168 | struct htable *t = h->table; | ||
| 169 | struct hbucket *n; | ||
| 170 | u32 i; | ||
| 171 | |||
| 172 | for (i = 0; i < jhash_size(t->htable_bits); i++) { | ||
| 173 | n = hbucket(t, i); | ||
| 174 | if (n->size) { | ||
| 175 | n->size = n->pos = 0; | ||
| 176 | /* FIXME: use slab cache */ | ||
| 177 | kfree(n->value); | ||
| 178 | } | ||
| 179 | } | ||
| 180 | #ifdef IP_SET_HASH_WITH_NETS | ||
| 181 | memset(h->nets, 0, sizeof(struct ip_set_hash_nets) | ||
| 182 | * SET_HOST_MASK(set->family)); | ||
| 183 | #endif | ||
| 184 | h->elements = 0; | ||
| 185 | } | ||
| 186 | |||
| 187 | /* Destroy a hash type of set */ | ||
| 188 | static void | ||
| 189 | ip_set_hash_destroy(struct ip_set *set) | ||
| 190 | { | ||
| 191 | struct ip_set_hash *h = set->data; | ||
| 192 | |||
| 193 | if (with_timeout(h->timeout)) | ||
| 194 | del_timer_sync(&h->gc); | ||
| 195 | |||
| 196 | ahash_destroy(h->table); | ||
| 197 | kfree(h); | ||
| 198 | |||
| 199 | set->data = NULL; | ||
| 200 | } | ||
| 201 | |||
| 202 | #define HKEY(data, initval, htable_bits) \ | ||
| 203 | (jhash2((u32 *)(data), sizeof(struct type_pf_elem)/sizeof(u32), initval) \ | ||
| 204 | & jhash_mask(htable_bits)) | ||
| 205 | |||
| 206 | #endif /* _IP_SET_AHASH_H */ | ||
| 207 | |||
| 208 | #define CONCAT(a, b, c) a##b##c | ||
| 209 | #define TOKEN(a, b, c) CONCAT(a, b, c) | ||
| 210 | |||
| 211 | /* Type/family dependent function prototypes */ | ||
| 212 | |||
| 213 | #define type_pf_data_equal TOKEN(TYPE, PF, _data_equal) | ||
| 214 | #define type_pf_data_isnull TOKEN(TYPE, PF, _data_isnull) | ||
| 215 | #define type_pf_data_copy TOKEN(TYPE, PF, _data_copy) | ||
| 216 | #define type_pf_data_zero_out TOKEN(TYPE, PF, _data_zero_out) | ||
| 217 | #define type_pf_data_netmask TOKEN(TYPE, PF, _data_netmask) | ||
| 218 | #define type_pf_data_list TOKEN(TYPE, PF, _data_list) | ||
| 219 | #define type_pf_data_tlist TOKEN(TYPE, PF, _data_tlist) | ||
| 220 | |||
| 221 | #define type_pf_elem TOKEN(TYPE, PF, _elem) | ||
| 222 | #define type_pf_telem TOKEN(TYPE, PF, _telem) | ||
| 223 | #define type_pf_data_timeout TOKEN(TYPE, PF, _data_timeout) | ||
| 224 | #define type_pf_data_expired TOKEN(TYPE, PF, _data_expired) | ||
| 225 | #define type_pf_data_timeout_set TOKEN(TYPE, PF, _data_timeout_set) | ||
| 226 | |||
| 227 | #define type_pf_elem_add TOKEN(TYPE, PF, _elem_add) | ||
| 228 | #define type_pf_add TOKEN(TYPE, PF, _add) | ||
| 229 | #define type_pf_del TOKEN(TYPE, PF, _del) | ||
| 230 | #define type_pf_test_cidrs TOKEN(TYPE, PF, _test_cidrs) | ||
| 231 | #define type_pf_test TOKEN(TYPE, PF, _test) | ||
| 232 | |||
| 233 | #define type_pf_elem_tadd TOKEN(TYPE, PF, _elem_tadd) | ||
| 234 | #define type_pf_del_telem TOKEN(TYPE, PF, _ahash_del_telem) | ||
| 235 | #define type_pf_expire TOKEN(TYPE, PF, _expire) | ||
| 236 | #define type_pf_tadd TOKEN(TYPE, PF, _tadd) | ||
| 237 | #define type_pf_tdel TOKEN(TYPE, PF, _tdel) | ||
| 238 | #define type_pf_ttest_cidrs TOKEN(TYPE, PF, _ahash_ttest_cidrs) | ||
| 239 | #define type_pf_ttest TOKEN(TYPE, PF, _ahash_ttest) | ||
| 240 | |||
| 241 | #define type_pf_resize TOKEN(TYPE, PF, _resize) | ||
| 242 | #define type_pf_tresize TOKEN(TYPE, PF, _tresize) | ||
| 243 | #define type_pf_flush ip_set_hash_flush | ||
| 244 | #define type_pf_destroy ip_set_hash_destroy | ||
| 245 | #define type_pf_head TOKEN(TYPE, PF, _head) | ||
| 246 | #define type_pf_list TOKEN(TYPE, PF, _list) | ||
| 247 | #define type_pf_tlist TOKEN(TYPE, PF, _tlist) | ||
| 248 | #define type_pf_same_set TOKEN(TYPE, PF, _same_set) | ||
| 249 | #define type_pf_kadt TOKEN(TYPE, PF, _kadt) | ||
| 250 | #define type_pf_uadt TOKEN(TYPE, PF, _uadt) | ||
| 251 | #define type_pf_gc TOKEN(TYPE, PF, _gc) | ||
| 252 | #define type_pf_gc_init TOKEN(TYPE, PF, _gc_init) | ||
| 253 | #define type_pf_variant TOKEN(TYPE, PF, _variant) | ||
| 254 | #define type_pf_tvariant TOKEN(TYPE, PF, _tvariant) | ||
| 255 | |||
| 256 | /* Flavour without timeout */ | ||
| 257 | |||
| 258 | /* Get the ith element from the array block n */ | ||
| 259 | #define ahash_data(n, i) \ | ||
| 260 | ((struct type_pf_elem *)((n)->value) + (i)) | ||
| 261 | |||
| 262 | /* Add an element to the hash table when resizing the set: | ||
| 263 | * we spare the maintenance of the internal counters. */ | ||
| 264 | static int | ||
| 265 | type_pf_elem_add(struct hbucket *n, const struct type_pf_elem *value) | ||
| 266 | { | ||
| 267 | if (n->pos >= n->size) { | ||
| 268 | void *tmp; | ||
| 269 | |||
| 270 | if (n->size >= AHASH_MAX_SIZE) | ||
| 271 | /* Trigger rehashing */ | ||
| 272 | return -EAGAIN; | ||
| 273 | |||
| 274 | tmp = kzalloc((n->size + AHASH_INIT_SIZE) | ||
| 275 | * sizeof(struct type_pf_elem), | ||
| 276 | GFP_ATOMIC); | ||
| 277 | if (!tmp) | ||
| 278 | return -ENOMEM; | ||
| 279 | if (n->size) { | ||
| 280 | memcpy(tmp, n->value, | ||
| 281 | sizeof(struct type_pf_elem) * n->size); | ||
| 282 | kfree(n->value); | ||
| 283 | } | ||
| 284 | n->value = tmp; | ||
| 285 | n->size += AHASH_INIT_SIZE; | ||
| 286 | } | ||
| 287 | type_pf_data_copy(ahash_data(n, n->pos++), value); | ||
| 288 | return 0; | ||
| 289 | } | ||
| 290 | |||
| 291 | /* Resize a hash: create a new hash table with doubling the hashsize | ||
| 292 | * and inserting the elements to it. Repeat until we succeed or | ||
| 293 | * fail due to memory pressures. */ | ||
| 294 | static int | ||
| 295 | type_pf_resize(struct ip_set *set, bool retried) | ||
| 296 | { | ||
| 297 | struct ip_set_hash *h = set->data; | ||
| 298 | struct htable *t, *orig = h->table; | ||
| 299 | u8 htable_bits = orig->htable_bits; | ||
| 300 | const struct type_pf_elem *data; | ||
| 301 | struct hbucket *n, *m; | ||
| 302 | u32 i, j; | ||
| 303 | int ret; | ||
| 304 | |||
| 305 | retry: | ||
| 306 | ret = 0; | ||
| 307 | htable_bits++; | ||
| 308 | pr_debug("attempt to resize set %s from %u to %u, t %p\n", | ||
| 309 | set->name, orig->htable_bits, htable_bits, orig); | ||
| 310 | if (!htable_bits) | ||
| 311 | /* In case we have plenty of memory :-) */ | ||
| 312 | return -IPSET_ERR_HASH_FULL; | ||
| 313 | t = ip_set_alloc(sizeof(*t) | ||
| 314 | + jhash_size(htable_bits) * sizeof(struct hbucket)); | ||
| 315 | if (!t) | ||
| 316 | return -ENOMEM; | ||
| 317 | t->htable_bits = htable_bits; | ||
| 318 | |||
| 319 | read_lock_bh(&set->lock); | ||
| 320 | for (i = 0; i < jhash_size(orig->htable_bits); i++) { | ||
| 321 | n = hbucket(orig, i); | ||
| 322 | for (j = 0; j < n->pos; j++) { | ||
| 323 | data = ahash_data(n, j); | ||
| 324 | m = hbucket(t, HKEY(data, h->initval, htable_bits)); | ||
| 325 | ret = type_pf_elem_add(m, data); | ||
| 326 | if (ret < 0) { | ||
| 327 | read_unlock_bh(&set->lock); | ||
| 328 | ahash_destroy(t); | ||
| 329 | if (ret == -EAGAIN) | ||
| 330 | goto retry; | ||
| 331 | return ret; | ||
| 332 | } | ||
| 333 | } | ||
| 334 | } | ||
| 335 | |||
| 336 | rcu_assign_pointer(h->table, t); | ||
| 337 | read_unlock_bh(&set->lock); | ||
| 338 | |||
| 339 | /* Give time to other readers of the set */ | ||
| 340 | synchronize_rcu_bh(); | ||
| 341 | |||
| 342 | pr_debug("set %s resized from %u (%p) to %u (%p)\n", set->name, | ||
| 343 | orig->htable_bits, orig, t->htable_bits, t); | ||
| 344 | ahash_destroy(orig); | ||
| 345 | |||
| 346 | return 0; | ||
| 347 | } | ||
| 348 | |||
| 349 | /* Add an element to a hash and update the internal counters when succeeded, | ||
| 350 | * otherwise report the proper error code. */ | ||
| 351 | static int | ||
| 352 | type_pf_add(struct ip_set *set, void *value, u32 timeout) | ||
| 353 | { | ||
| 354 | struct ip_set_hash *h = set->data; | ||
| 355 | struct htable *t; | ||
| 356 | const struct type_pf_elem *d = value; | ||
| 357 | struct hbucket *n; | ||
| 358 | int i, ret = 0; | ||
| 359 | u32 key; | ||
| 360 | |||
| 361 | if (h->elements >= h->maxelem) | ||
| 362 | return -IPSET_ERR_HASH_FULL; | ||
| 363 | |||
| 364 | rcu_read_lock_bh(); | ||
| 365 | t = rcu_dereference_bh(h->table); | ||
| 366 | key = HKEY(value, h->initval, t->htable_bits); | ||
| 367 | n = hbucket(t, key); | ||
| 368 | for (i = 0; i < n->pos; i++) | ||
| 369 | if (type_pf_data_equal(ahash_data(n, i), d)) { | ||
| 370 | ret = -IPSET_ERR_EXIST; | ||
| 371 | goto out; | ||
| 372 | } | ||
| 373 | |||
| 374 | ret = type_pf_elem_add(n, value); | ||
| 375 | if (ret != 0) | ||
| 376 | goto out; | ||
| 377 | |||
| 378 | #ifdef IP_SET_HASH_WITH_NETS | ||
| 379 | add_cidr(h, d->cidr, HOST_MASK); | ||
| 380 | #endif | ||
| 381 | h->elements++; | ||
| 382 | out: | ||
| 383 | rcu_read_unlock_bh(); | ||
| 384 | return ret; | ||
| 385 | } | ||
| 386 | |||
| 387 | /* Delete an element from the hash: swap it with the last element | ||
| 388 | * and free up space if possible. | ||
| 389 | */ | ||
| 390 | static int | ||
| 391 | type_pf_del(struct ip_set *set, void *value, u32 timeout) | ||
| 392 | { | ||
| 393 | struct ip_set_hash *h = set->data; | ||
| 394 | struct htable *t = h->table; | ||
| 395 | const struct type_pf_elem *d = value; | ||
| 396 | struct hbucket *n; | ||
| 397 | int i; | ||
| 398 | struct type_pf_elem *data; | ||
| 399 | u32 key; | ||
| 400 | |||
| 401 | key = HKEY(value, h->initval, t->htable_bits); | ||
| 402 | n = hbucket(t, key); | ||
| 403 | for (i = 0; i < n->pos; i++) { | ||
| 404 | data = ahash_data(n, i); | ||
| 405 | if (!type_pf_data_equal(data, d)) | ||
| 406 | continue; | ||
| 407 | if (i != n->pos - 1) | ||
| 408 | /* Not last one */ | ||
| 409 | type_pf_data_copy(data, ahash_data(n, n->pos - 1)); | ||
| 410 | |||
| 411 | n->pos--; | ||
| 412 | h->elements--; | ||
| 413 | #ifdef IP_SET_HASH_WITH_NETS | ||
| 414 | del_cidr(h, d->cidr, HOST_MASK); | ||
| 415 | #endif | ||
| 416 | if (n->pos + AHASH_INIT_SIZE < n->size) { | ||
| 417 | void *tmp = kzalloc((n->size - AHASH_INIT_SIZE) | ||
| 418 | * sizeof(struct type_pf_elem), | ||
| 419 | GFP_ATOMIC); | ||
| 420 | if (!tmp) | ||
| 421 | return 0; | ||
| 422 | n->size -= AHASH_INIT_SIZE; | ||
| 423 | memcpy(tmp, n->value, | ||
| 424 | n->size * sizeof(struct type_pf_elem)); | ||
| 425 | kfree(n->value); | ||
| 426 | n->value = tmp; | ||
| 427 | } | ||
| 428 | return 0; | ||
| 429 | } | ||
| 430 | |||
| 431 | return -IPSET_ERR_EXIST; | ||
| 432 | } | ||
| 433 | |||
| 434 | #ifdef IP_SET_HASH_WITH_NETS | ||
| 435 | |||
| 436 | /* Special test function which takes into account the different network | ||
| 437 | * sizes added to the set */ | ||
| 438 | static int | ||
| 439 | type_pf_test_cidrs(struct ip_set *set, struct type_pf_elem *d, u32 timeout) | ||
| 440 | { | ||
| 441 | struct ip_set_hash *h = set->data; | ||
| 442 | struct htable *t = h->table; | ||
| 443 | struct hbucket *n; | ||
| 444 | const struct type_pf_elem *data; | ||
| 445 | int i, j = 0; | ||
| 446 | u32 key; | ||
| 447 | u8 host_mask = SET_HOST_MASK(set->family); | ||
| 448 | |||
| 449 | pr_debug("test by nets\n"); | ||
| 450 | for (; j < host_mask && h->nets[j].cidr; j++) { | ||
| 451 | type_pf_data_netmask(d, h->nets[j].cidr); | ||
| 452 | key = HKEY(d, h->initval, t->htable_bits); | ||
| 453 | n = hbucket(t, key); | ||
| 454 | for (i = 0; i < n->pos; i++) { | ||
| 455 | data = ahash_data(n, i); | ||
| 456 | if (type_pf_data_equal(data, d)) | ||
| 457 | return 1; | ||
| 458 | } | ||
| 459 | } | ||
| 460 | return 0; | ||
| 461 | } | ||
| 462 | #endif | ||
| 463 | |||
| 464 | /* Test whether the element is added to the set */ | ||
| 465 | static int | ||
| 466 | type_pf_test(struct ip_set *set, void *value, u32 timeout) | ||
| 467 | { | ||
| 468 | struct ip_set_hash *h = set->data; | ||
| 469 | struct htable *t = h->table; | ||
| 470 | struct type_pf_elem *d = value; | ||
| 471 | struct hbucket *n; | ||
| 472 | const struct type_pf_elem *data; | ||
| 473 | int i; | ||
| 474 | u32 key; | ||
| 475 | |||
| 476 | #ifdef IP_SET_HASH_WITH_NETS | ||
| 477 | /* If we test an IP address and not a network address, | ||
| 478 | * try all possible network sizes */ | ||
| 479 | if (d->cidr == SET_HOST_MASK(set->family)) | ||
| 480 | return type_pf_test_cidrs(set, d, timeout); | ||
| 481 | #endif | ||
| 482 | |||
| 483 | key = HKEY(d, h->initval, t->htable_bits); | ||
| 484 | n = hbucket(t, key); | ||
| 485 | for (i = 0; i < n->pos; i++) { | ||
| 486 | data = ahash_data(n, i); | ||
| 487 | if (type_pf_data_equal(data, d)) | ||
| 488 | return 1; | ||
| 489 | } | ||
| 490 | return 0; | ||
| 491 | } | ||
| 492 | |||
| 493 | /* Reply a HEADER request: fill out the header part of the set */ | ||
| 494 | static int | ||
| 495 | type_pf_head(struct ip_set *set, struct sk_buff *skb) | ||
| 496 | { | ||
| 497 | const struct ip_set_hash *h = set->data; | ||
| 498 | struct nlattr *nested; | ||
| 499 | size_t memsize; | ||
| 500 | |||
| 501 | read_lock_bh(&set->lock); | ||
| 502 | memsize = ahash_memsize(h, with_timeout(h->timeout) | ||
| 503 | ? sizeof(struct type_pf_telem) | ||
| 504 | : sizeof(struct type_pf_elem), | ||
| 505 | set->family == AF_INET ? 32 : 128); | ||
| 506 | read_unlock_bh(&set->lock); | ||
| 507 | |||
| 508 | nested = ipset_nest_start(skb, IPSET_ATTR_DATA); | ||
| 509 | if (!nested) | ||
| 510 | goto nla_put_failure; | ||
| 511 | NLA_PUT_NET32(skb, IPSET_ATTR_HASHSIZE, | ||
| 512 | htonl(jhash_size(h->table->htable_bits))); | ||
| 513 | NLA_PUT_NET32(skb, IPSET_ATTR_MAXELEM, htonl(h->maxelem)); | ||
| 514 | #ifdef IP_SET_HASH_WITH_NETMASK | ||
| 515 | if (h->netmask != HOST_MASK) | ||
| 516 | NLA_PUT_U8(skb, IPSET_ATTR_NETMASK, h->netmask); | ||
| 517 | #endif | ||
| 518 | NLA_PUT_NET32(skb, IPSET_ATTR_REFERENCES, | ||
| 519 | htonl(atomic_read(&set->ref) - 1)); | ||
| 520 | NLA_PUT_NET32(skb, IPSET_ATTR_MEMSIZE, htonl(memsize)); | ||
| 521 | if (with_timeout(h->timeout)) | ||
| 522 | NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT, htonl(h->timeout)); | ||
| 523 | ipset_nest_end(skb, nested); | ||
| 524 | |||
| 525 | return 0; | ||
| 526 | nla_put_failure: | ||
| 527 | return -EMSGSIZE; | ||
| 528 | } | ||
| 529 | |||
| 530 | /* Reply a LIST/SAVE request: dump the elements of the specified set */ | ||
| 531 | static int | ||
| 532 | type_pf_list(const struct ip_set *set, | ||
| 533 | struct sk_buff *skb, struct netlink_callback *cb) | ||
| 534 | { | ||
| 535 | const struct ip_set_hash *h = set->data; | ||
| 536 | const struct htable *t = h->table; | ||
| 537 | struct nlattr *atd, *nested; | ||
| 538 | const struct hbucket *n; | ||
| 539 | const struct type_pf_elem *data; | ||
| 540 | u32 first = cb->args[2]; | ||
| 541 | /* We assume that one hash bucket fills into one page */ | ||
| 542 | void *incomplete; | ||
| 543 | int i; | ||
| 544 | |||
| 545 | atd = ipset_nest_start(skb, IPSET_ATTR_ADT); | ||
| 546 | if (!atd) | ||
| 547 | return -EMSGSIZE; | ||
| 548 | pr_debug("list hash set %s\n", set->name); | ||
| 549 | for (; cb->args[2] < jhash_size(t->htable_bits); cb->args[2]++) { | ||
| 550 | incomplete = skb_tail_pointer(skb); | ||
| 551 | n = hbucket(t, cb->args[2]); | ||
| 552 | pr_debug("cb->args[2]: %lu, t %p n %p\n", cb->args[2], t, n); | ||
| 553 | for (i = 0; i < n->pos; i++) { | ||
| 554 | data = ahash_data(n, i); | ||
| 555 | pr_debug("list hash %lu hbucket %p i %u, data %p\n", | ||
| 556 | cb->args[2], n, i, data); | ||
| 557 | nested = ipset_nest_start(skb, IPSET_ATTR_DATA); | ||
| 558 | if (!nested) { | ||
| 559 | if (cb->args[2] == first) { | ||
| 560 | nla_nest_cancel(skb, atd); | ||
| 561 | return -EMSGSIZE; | ||
| 562 | } else | ||
| 563 | goto nla_put_failure; | ||
| 564 | } | ||
| 565 | if (type_pf_data_list(skb, data)) | ||
| 566 | goto nla_put_failure; | ||
| 567 | ipset_nest_end(skb, nested); | ||
| 568 | } | ||
| 569 | } | ||
| 570 | ipset_nest_end(skb, atd); | ||
| 571 | /* Set listing finished */ | ||
| 572 | cb->args[2] = 0; | ||
| 573 | |||
| 574 | return 0; | ||
| 575 | |||
| 576 | nla_put_failure: | ||
| 577 | nlmsg_trim(skb, incomplete); | ||
| 578 | ipset_nest_end(skb, atd); | ||
| 579 | if (unlikely(first == cb->args[2])) { | ||
| 580 | pr_warning("Can't list set %s: one bucket does not fit into " | ||
| 581 | "a message. Please report it!\n", set->name); | ||
| 582 | cb->args[2] = 0; | ||
| 583 | return -EMSGSIZE; | ||
| 584 | } | ||
| 585 | return 0; | ||
| 586 | } | ||
| 587 | |||
| 588 | static int | ||
| 589 | type_pf_kadt(struct ip_set *set, const struct sk_buff * skb, | ||
| 590 | enum ipset_adt adt, u8 pf, u8 dim, u8 flags); | ||
| 591 | static int | ||
| 592 | type_pf_uadt(struct ip_set *set, struct nlattr *tb[], | ||
| 593 | enum ipset_adt adt, u32 *lineno, u32 flags); | ||
| 594 | |||
| 595 | static const struct ip_set_type_variant type_pf_variant = { | ||
| 596 | .kadt = type_pf_kadt, | ||
| 597 | .uadt = type_pf_uadt, | ||
| 598 | .adt = { | ||
| 599 | [IPSET_ADD] = type_pf_add, | ||
| 600 | [IPSET_DEL] = type_pf_del, | ||
| 601 | [IPSET_TEST] = type_pf_test, | ||
| 602 | }, | ||
| 603 | .destroy = type_pf_destroy, | ||
| 604 | .flush = type_pf_flush, | ||
| 605 | .head = type_pf_head, | ||
| 606 | .list = type_pf_list, | ||
| 607 | .resize = type_pf_resize, | ||
| 608 | .same_set = type_pf_same_set, | ||
| 609 | }; | ||
| 610 | |||
| 611 | /* Flavour with timeout support */ | ||
| 612 | |||
| 613 | #define ahash_tdata(n, i) \ | ||
| 614 | (struct type_pf_elem *)((struct type_pf_telem *)((n)->value) + (i)) | ||
| 615 | |||
| 616 | static inline u32 | ||
| 617 | type_pf_data_timeout(const struct type_pf_elem *data) | ||
| 618 | { | ||
| 619 | const struct type_pf_telem *tdata = | ||
| 620 | (const struct type_pf_telem *) data; | ||
| 621 | |||
| 622 | return tdata->timeout; | ||
| 623 | } | ||
| 624 | |||
| 625 | static inline bool | ||
| 626 | type_pf_data_expired(const struct type_pf_elem *data) | ||
| 627 | { | ||
| 628 | const struct type_pf_telem *tdata = | ||
| 629 | (const struct type_pf_telem *) data; | ||
| 630 | |||
| 631 | return ip_set_timeout_expired(tdata->timeout); | ||
| 632 | } | ||
| 633 | |||
| 634 | static inline void | ||
| 635 | type_pf_data_timeout_set(struct type_pf_elem *data, u32 timeout) | ||
| 636 | { | ||
| 637 | struct type_pf_telem *tdata = (struct type_pf_telem *) data; | ||
| 638 | |||
| 639 | tdata->timeout = ip_set_timeout_set(timeout); | ||
| 640 | } | ||
| 641 | |||
| 642 | static int | ||
| 643 | type_pf_elem_tadd(struct hbucket *n, const struct type_pf_elem *value, | ||
| 644 | u32 timeout) | ||
| 645 | { | ||
| 646 | struct type_pf_elem *data; | ||
| 647 | |||
| 648 | if (n->pos >= n->size) { | ||
| 649 | void *tmp; | ||
| 650 | |||
| 651 | if (n->size >= AHASH_MAX_SIZE) | ||
| 652 | /* Trigger rehashing */ | ||
| 653 | return -EAGAIN; | ||
| 654 | |||
| 655 | tmp = kzalloc((n->size + AHASH_INIT_SIZE) | ||
| 656 | * sizeof(struct type_pf_telem), | ||
| 657 | GFP_ATOMIC); | ||
| 658 | if (!tmp) | ||
| 659 | return -ENOMEM; | ||
| 660 | if (n->size) { | ||
| 661 | memcpy(tmp, n->value, | ||
| 662 | sizeof(struct type_pf_telem) * n->size); | ||
| 663 | kfree(n->value); | ||
| 664 | } | ||
| 665 | n->value = tmp; | ||
| 666 | n->size += AHASH_INIT_SIZE; | ||
| 667 | } | ||
| 668 | data = ahash_tdata(n, n->pos++); | ||
| 669 | type_pf_data_copy(data, value); | ||
| 670 | type_pf_data_timeout_set(data, timeout); | ||
| 671 | return 0; | ||
| 672 | } | ||
| 673 | |||
| 674 | /* Delete expired elements from the hashtable */ | ||
| 675 | static void | ||
| 676 | type_pf_expire(struct ip_set_hash *h) | ||
| 677 | { | ||
| 678 | struct htable *t = h->table; | ||
| 679 | struct hbucket *n; | ||
| 680 | struct type_pf_elem *data; | ||
| 681 | u32 i; | ||
| 682 | int j; | ||
| 683 | |||
| 684 | for (i = 0; i < jhash_size(t->htable_bits); i++) { | ||
| 685 | n = hbucket(t, i); | ||
| 686 | for (j = 0; j < n->pos; j++) { | ||
| 687 | data = ahash_tdata(n, j); | ||
| 688 | if (type_pf_data_expired(data)) { | ||
| 689 | pr_debug("expired %u/%u\n", i, j); | ||
| 690 | #ifdef IP_SET_HASH_WITH_NETS | ||
| 691 | del_cidr(h, data->cidr, HOST_MASK); | ||
| 692 | #endif | ||
| 693 | if (j != n->pos - 1) | ||
| 694 | /* Not last one */ | ||
| 695 | type_pf_data_copy(data, | ||
| 696 | ahash_tdata(n, n->pos - 1)); | ||
| 697 | n->pos--; | ||
| 698 | h->elements--; | ||
| 699 | } | ||
| 700 | } | ||
| 701 | if (n->pos + AHASH_INIT_SIZE < n->size) { | ||
| 702 | void *tmp = kzalloc((n->size - AHASH_INIT_SIZE) | ||
| 703 | * sizeof(struct type_pf_telem), | ||
| 704 | GFP_ATOMIC); | ||
| 705 | if (!tmp) | ||
| 706 | /* Still try to delete expired elements */ | ||
| 707 | continue; | ||
| 708 | n->size -= AHASH_INIT_SIZE; | ||
| 709 | memcpy(tmp, n->value, | ||
| 710 | n->size * sizeof(struct type_pf_telem)); | ||
| 711 | kfree(n->value); | ||
| 712 | n->value = tmp; | ||
| 713 | } | ||
| 714 | } | ||
| 715 | } | ||
| 716 | |||
| 717 | static int | ||
| 718 | type_pf_tresize(struct ip_set *set, bool retried) | ||
| 719 | { | ||
| 720 | struct ip_set_hash *h = set->data; | ||
| 721 | struct htable *t, *orig = h->table; | ||
| 722 | u8 htable_bits = orig->htable_bits; | ||
| 723 | const struct type_pf_elem *data; | ||
| 724 | struct hbucket *n, *m; | ||
| 725 | u32 i, j; | ||
| 726 | int ret; | ||
| 727 | |||
| 728 | /* Try to cleanup once */ | ||
| 729 | if (!retried) { | ||
| 730 | i = h->elements; | ||
| 731 | write_lock_bh(&set->lock); | ||
| 732 | type_pf_expire(set->data); | ||
| 733 | write_unlock_bh(&set->lock); | ||
| 734 | if (h->elements < i) | ||
| 735 | return 0; | ||
| 736 | } | ||
| 737 | |||
| 738 | retry: | ||
| 739 | ret = 0; | ||
| 740 | htable_bits++; | ||
| 741 | if (!htable_bits) | ||
| 742 | /* In case we have plenty of memory :-) */ | ||
| 743 | return -IPSET_ERR_HASH_FULL; | ||
| 744 | t = ip_set_alloc(sizeof(*t) | ||
| 745 | + jhash_size(htable_bits) * sizeof(struct hbucket)); | ||
| 746 | if (!t) | ||
| 747 | return -ENOMEM; | ||
| 748 | t->htable_bits = htable_bits; | ||
| 749 | |||
| 750 | read_lock_bh(&set->lock); | ||
| 751 | for (i = 0; i < jhash_size(orig->htable_bits); i++) { | ||
| 752 | n = hbucket(orig, i); | ||
| 753 | for (j = 0; j < n->pos; j++) { | ||
| 754 | data = ahash_tdata(n, j); | ||
| 755 | m = hbucket(t, HKEY(data, h->initval, htable_bits)); | ||
| 756 | ret = type_pf_elem_tadd(m, data, | ||
| 757 | type_pf_data_timeout(data)); | ||
| 758 | if (ret < 0) { | ||
| 759 | read_unlock_bh(&set->lock); | ||
| 760 | ahash_destroy(t); | ||
| 761 | if (ret == -EAGAIN) | ||
| 762 | goto retry; | ||
| 763 | return ret; | ||
| 764 | } | ||
| 765 | } | ||
| 766 | } | ||
| 767 | |||
| 768 | rcu_assign_pointer(h->table, t); | ||
| 769 | read_unlock_bh(&set->lock); | ||
| 770 | |||
| 771 | /* Give time to other readers of the set */ | ||
| 772 | synchronize_rcu_bh(); | ||
| 773 | |||
| 774 | ahash_destroy(orig); | ||
| 775 | |||
| 776 | return 0; | ||
| 777 | } | ||
| 778 | |||
| 779 | static int | ||
| 780 | type_pf_tadd(struct ip_set *set, void *value, u32 timeout) | ||
| 781 | { | ||
| 782 | struct ip_set_hash *h = set->data; | ||
| 783 | struct htable *t = h->table; | ||
| 784 | const struct type_pf_elem *d = value; | ||
| 785 | struct hbucket *n; | ||
| 786 | struct type_pf_elem *data; | ||
| 787 | int ret = 0, i, j = AHASH_MAX_SIZE + 1; | ||
| 788 | u32 key; | ||
| 789 | |||
| 790 | if (h->elements >= h->maxelem) | ||
| 791 | /* FIXME: when set is full, we slow down here */ | ||
| 792 | type_pf_expire(h); | ||
| 793 | if (h->elements >= h->maxelem) | ||
| 794 | return -IPSET_ERR_HASH_FULL; | ||
| 795 | |||
| 796 | rcu_read_lock_bh(); | ||
| 797 | t = rcu_dereference_bh(h->table); | ||
| 798 | key = HKEY(d, h->initval, t->htable_bits); | ||
| 799 | n = hbucket(t, key); | ||
| 800 | for (i = 0; i < n->pos; i++) { | ||
| 801 | data = ahash_tdata(n, i); | ||
| 802 | if (type_pf_data_equal(data, d)) { | ||
| 803 | if (type_pf_data_expired(data)) | ||
| 804 | j = i; | ||
| 805 | else { | ||
| 806 | ret = -IPSET_ERR_EXIST; | ||
| 807 | goto out; | ||
| 808 | } | ||
| 809 | } else if (j == AHASH_MAX_SIZE + 1 && | ||
| 810 | type_pf_data_expired(data)) | ||
| 811 | j = i; | ||
| 812 | } | ||
| 813 | if (j != AHASH_MAX_SIZE + 1) { | ||
| 814 | data = ahash_tdata(n, j); | ||
| 815 | #ifdef IP_SET_HASH_WITH_NETS | ||
| 816 | del_cidr(h, data->cidr, HOST_MASK); | ||
| 817 | add_cidr(h, d->cidr, HOST_MASK); | ||
| 818 | #endif | ||
| 819 | type_pf_data_copy(data, d); | ||
| 820 | type_pf_data_timeout_set(data, timeout); | ||
| 821 | goto out; | ||
| 822 | } | ||
| 823 | ret = type_pf_elem_tadd(n, d, timeout); | ||
| 824 | if (ret != 0) | ||
| 825 | goto out; | ||
| 826 | |||
| 827 | #ifdef IP_SET_HASH_WITH_NETS | ||
| 828 | add_cidr(h, d->cidr, HOST_MASK); | ||
| 829 | #endif | ||
| 830 | h->elements++; | ||
| 831 | out: | ||
| 832 | rcu_read_unlock_bh(); | ||
| 833 | return ret; | ||
| 834 | } | ||
| 835 | |||
| 836 | static int | ||
| 837 | type_pf_tdel(struct ip_set *set, void *value, u32 timeout) | ||
| 838 | { | ||
| 839 | struct ip_set_hash *h = set->data; | ||
| 840 | struct htable *t = h->table; | ||
| 841 | const struct type_pf_elem *d = value; | ||
| 842 | struct hbucket *n; | ||
| 843 | int i, ret = 0; | ||
| 844 | struct type_pf_elem *data; | ||
| 845 | u32 key; | ||
| 846 | |||
| 847 | key = HKEY(value, h->initval, t->htable_bits); | ||
| 848 | n = hbucket(t, key); | ||
| 849 | for (i = 0; i < n->pos; i++) { | ||
| 850 | data = ahash_tdata(n, i); | ||
| 851 | if (!type_pf_data_equal(data, d)) | ||
| 852 | continue; | ||
| 853 | if (type_pf_data_expired(data)) | ||
| 854 | ret = -IPSET_ERR_EXIST; | ||
| 855 | if (i != n->pos - 1) | ||
| 856 | /* Not last one */ | ||
| 857 | type_pf_data_copy(data, ahash_tdata(n, n->pos - 1)); | ||
| 858 | |||
| 859 | n->pos--; | ||
| 860 | h->elements--; | ||
| 861 | #ifdef IP_SET_HASH_WITH_NETS | ||
| 862 | del_cidr(h, d->cidr, HOST_MASK); | ||
| 863 | #endif | ||
| 864 | if (n->pos + AHASH_INIT_SIZE < n->size) { | ||
| 865 | void *tmp = kzalloc((n->size - AHASH_INIT_SIZE) | ||
| 866 | * sizeof(struct type_pf_telem), | ||
| 867 | GFP_ATOMIC); | ||
| 868 | if (!tmp) | ||
| 869 | return 0; | ||
| 870 | n->size -= AHASH_INIT_SIZE; | ||
| 871 | memcpy(tmp, n->value, | ||
| 872 | n->size * sizeof(struct type_pf_telem)); | ||
| 873 | kfree(n->value); | ||
| 874 | n->value = tmp; | ||
| 875 | } | ||
| 876 | return 0; | ||
| 877 | } | ||
| 878 | |||
| 879 | return -IPSET_ERR_EXIST; | ||
| 880 | } | ||
| 881 | |||
| 882 | #ifdef IP_SET_HASH_WITH_NETS | ||
| 883 | static int | ||
| 884 | type_pf_ttest_cidrs(struct ip_set *set, struct type_pf_elem *d, u32 timeout) | ||
| 885 | { | ||
| 886 | struct ip_set_hash *h = set->data; | ||
| 887 | struct htable *t = h->table; | ||
| 888 | struct type_pf_elem *data; | ||
| 889 | struct hbucket *n; | ||
| 890 | int i, j = 0; | ||
| 891 | u32 key; | ||
| 892 | u8 host_mask = SET_HOST_MASK(set->family); | ||
| 893 | |||
| 894 | for (; j < host_mask && h->nets[j].cidr; j++) { | ||
| 895 | type_pf_data_netmask(d, h->nets[j].cidr); | ||
| 896 | key = HKEY(d, h->initval, t->htable_bits); | ||
| 897 | n = hbucket(t, key); | ||
| 898 | for (i = 0; i < n->pos; i++) { | ||
| 899 | data = ahash_tdata(n, i); | ||
| 900 | if (type_pf_data_equal(data, d)) | ||
| 901 | return !type_pf_data_expired(data); | ||
| 902 | } | ||
| 903 | } | ||
| 904 | return 0; | ||
| 905 | } | ||
| 906 | #endif | ||
| 907 | |||
| 908 | static int | ||
| 909 | type_pf_ttest(struct ip_set *set, void *value, u32 timeout) | ||
| 910 | { | ||
| 911 | struct ip_set_hash *h = set->data; | ||
| 912 | struct htable *t = h->table; | ||
| 913 | struct type_pf_elem *data, *d = value; | ||
| 914 | struct hbucket *n; | ||
| 915 | int i; | ||
| 916 | u32 key; | ||
| 917 | |||
| 918 | #ifdef IP_SET_HASH_WITH_NETS | ||
| 919 | if (d->cidr == SET_HOST_MASK(set->family)) | ||
| 920 | return type_pf_ttest_cidrs(set, d, timeout); | ||
| 921 | #endif | ||
| 922 | key = HKEY(d, h->initval, t->htable_bits); | ||
| 923 | n = hbucket(t, key); | ||
| 924 | for (i = 0; i < n->pos; i++) { | ||
| 925 | data = ahash_tdata(n, i); | ||
| 926 | if (type_pf_data_equal(data, d)) | ||
| 927 | return !type_pf_data_expired(data); | ||
| 928 | } | ||
| 929 | return 0; | ||
| 930 | } | ||
| 931 | |||
| 932 | static int | ||
| 933 | type_pf_tlist(const struct ip_set *set, | ||
| 934 | struct sk_buff *skb, struct netlink_callback *cb) | ||
| 935 | { | ||
| 936 | const struct ip_set_hash *h = set->data; | ||
| 937 | const struct htable *t = h->table; | ||
| 938 | struct nlattr *atd, *nested; | ||
| 939 | const struct hbucket *n; | ||
| 940 | const struct type_pf_elem *data; | ||
| 941 | u32 first = cb->args[2]; | ||
| 942 | /* We assume that one hash bucket fills into one page */ | ||
| 943 | void *incomplete; | ||
| 944 | int i; | ||
| 945 | |||
| 946 | atd = ipset_nest_start(skb, IPSET_ATTR_ADT); | ||
| 947 | if (!atd) | ||
| 948 | return -EMSGSIZE; | ||
| 949 | for (; cb->args[2] < jhash_size(t->htable_bits); cb->args[2]++) { | ||
| 950 | incomplete = skb_tail_pointer(skb); | ||
| 951 | n = hbucket(t, cb->args[2]); | ||
| 952 | for (i = 0; i < n->pos; i++) { | ||
| 953 | data = ahash_tdata(n, i); | ||
| 954 | pr_debug("list %p %u\n", n, i); | ||
| 955 | if (type_pf_data_expired(data)) | ||
| 956 | continue; | ||
| 957 | pr_debug("do list %p %u\n", n, i); | ||
| 958 | nested = ipset_nest_start(skb, IPSET_ATTR_DATA); | ||
| 959 | if (!nested) { | ||
| 960 | if (cb->args[2] == first) { | ||
| 961 | nla_nest_cancel(skb, atd); | ||
| 962 | return -EMSGSIZE; | ||
| 963 | } else | ||
| 964 | goto nla_put_failure; | ||
| 965 | } | ||
| 966 | if (type_pf_data_tlist(skb, data)) | ||
| 967 | goto nla_put_failure; | ||
| 968 | ipset_nest_end(skb, nested); | ||
| 969 | } | ||
| 970 | } | ||
| 971 | ipset_nest_end(skb, atd); | ||
| 972 | /* Set listing finished */ | ||
| 973 | cb->args[2] = 0; | ||
| 974 | |||
| 975 | return 0; | ||
| 976 | |||
| 977 | nla_put_failure: | ||
| 978 | nlmsg_trim(skb, incomplete); | ||
| 979 | ipset_nest_end(skb, atd); | ||
| 980 | if (unlikely(first == cb->args[2])) { | ||
| 981 | pr_warning("Can't list set %s: one bucket does not fit into " | ||
| 982 | "a message. Please report it!\n", set->name); | ||
| 983 | cb->args[2] = 0; | ||
| 984 | return -EMSGSIZE; | ||
| 985 | } | ||
| 986 | return 0; | ||
| 987 | } | ||
| 988 | |||
| 989 | static const struct ip_set_type_variant type_pf_tvariant = { | ||
| 990 | .kadt = type_pf_kadt, | ||
| 991 | .uadt = type_pf_uadt, | ||
| 992 | .adt = { | ||
| 993 | [IPSET_ADD] = type_pf_tadd, | ||
| 994 | [IPSET_DEL] = type_pf_tdel, | ||
| 995 | [IPSET_TEST] = type_pf_ttest, | ||
| 996 | }, | ||
| 997 | .destroy = type_pf_destroy, | ||
| 998 | .flush = type_pf_flush, | ||
| 999 | .head = type_pf_head, | ||
| 1000 | .list = type_pf_tlist, | ||
| 1001 | .resize = type_pf_tresize, | ||
| 1002 | .same_set = type_pf_same_set, | ||
| 1003 | }; | ||
| 1004 | |||
| 1005 | static void | ||
| 1006 | type_pf_gc(unsigned long ul_set) | ||
| 1007 | { | ||
| 1008 | struct ip_set *set = (struct ip_set *) ul_set; | ||
| 1009 | struct ip_set_hash *h = set->data; | ||
| 1010 | |||
| 1011 | pr_debug("called\n"); | ||
| 1012 | write_lock_bh(&set->lock); | ||
| 1013 | type_pf_expire(h); | ||
| 1014 | write_unlock_bh(&set->lock); | ||
| 1015 | |||
| 1016 | h->gc.expires = jiffies + IPSET_GC_PERIOD(h->timeout) * HZ; | ||
| 1017 | add_timer(&h->gc); | ||
| 1018 | } | ||
| 1019 | |||
| 1020 | static void | ||
| 1021 | type_pf_gc_init(struct ip_set *set) | ||
| 1022 | { | ||
| 1023 | struct ip_set_hash *h = set->data; | ||
| 1024 | |||
| 1025 | init_timer(&h->gc); | ||
| 1026 | h->gc.data = (unsigned long) set; | ||
| 1027 | h->gc.function = type_pf_gc; | ||
| 1028 | h->gc.expires = jiffies + IPSET_GC_PERIOD(h->timeout) * HZ; | ||
| 1029 | add_timer(&h->gc); | ||
| 1030 | pr_debug("gc initialized, run in every %u\n", | ||
| 1031 | IPSET_GC_PERIOD(h->timeout)); | ||
| 1032 | } | ||
| 1033 | |||
| 1034 | #undef type_pf_data_equal | ||
| 1035 | #undef type_pf_data_isnull | ||
| 1036 | #undef type_pf_data_copy | ||
| 1037 | #undef type_pf_data_zero_out | ||
| 1038 | #undef type_pf_data_list | ||
| 1039 | #undef type_pf_data_tlist | ||
| 1040 | |||
| 1041 | #undef type_pf_elem | ||
| 1042 | #undef type_pf_telem | ||
| 1043 | #undef type_pf_data_timeout | ||
| 1044 | #undef type_pf_data_expired | ||
| 1045 | #undef type_pf_data_netmask | ||
| 1046 | #undef type_pf_data_timeout_set | ||
| 1047 | |||
| 1048 | #undef type_pf_elem_add | ||
| 1049 | #undef type_pf_add | ||
| 1050 | #undef type_pf_del | ||
| 1051 | #undef type_pf_test_cidrs | ||
| 1052 | #undef type_pf_test | ||
| 1053 | |||
| 1054 | #undef type_pf_elem_tadd | ||
| 1055 | #undef type_pf_expire | ||
| 1056 | #undef type_pf_tadd | ||
| 1057 | #undef type_pf_tdel | ||
| 1058 | #undef type_pf_ttest_cidrs | ||
| 1059 | #undef type_pf_ttest | ||
| 1060 | |||
| 1061 | #undef type_pf_resize | ||
| 1062 | #undef type_pf_tresize | ||
| 1063 | #undef type_pf_flush | ||
| 1064 | #undef type_pf_destroy | ||
| 1065 | #undef type_pf_head | ||
| 1066 | #undef type_pf_list | ||
| 1067 | #undef type_pf_tlist | ||
| 1068 | #undef type_pf_same_set | ||
| 1069 | #undef type_pf_kadt | ||
| 1070 | #undef type_pf_uadt | ||
| 1071 | #undef type_pf_gc | ||
| 1072 | #undef type_pf_gc_init | ||
| 1073 | #undef type_pf_variant | ||
| 1074 | #undef type_pf_tvariant | ||
diff --git a/include/linux/netfilter/ipset/ip_set_bitmap.h b/include/linux/netfilter/ipset/ip_set_bitmap.h new file mode 100644 index 000000000000..61a9e8746c83 --- /dev/null +++ b/include/linux/netfilter/ipset/ip_set_bitmap.h | |||
| @@ -0,0 +1,31 @@ | |||
| 1 | #ifndef __IP_SET_BITMAP_H | ||
| 2 | #define __IP_SET_BITMAP_H | ||
| 3 | |||
| 4 | /* Bitmap type specific error codes */ | ||
| 5 | enum { | ||
| 6 | /* The element is out of the range of the set */ | ||
| 7 | IPSET_ERR_BITMAP_RANGE = IPSET_ERR_TYPE_SPECIFIC, | ||
| 8 | /* The range exceeds the size limit of the set type */ | ||
| 9 | IPSET_ERR_BITMAP_RANGE_SIZE, | ||
| 10 | }; | ||
| 11 | |||
| 12 | #ifdef __KERNEL__ | ||
| 13 | #define IPSET_BITMAP_MAX_RANGE 0x0000FFFF | ||
| 14 | |||
| 15 | /* Common functions */ | ||
| 16 | |||
| 17 | static inline u32 | ||
| 18 | range_to_mask(u32 from, u32 to, u8 *bits) | ||
| 19 | { | ||
| 20 | u32 mask = 0xFFFFFFFE; | ||
| 21 | |||
| 22 | *bits = 32; | ||
| 23 | while (--(*bits) > 0 && mask && (to & mask) != from) | ||
| 24 | mask <<= 1; | ||
| 25 | |||
| 26 | return mask; | ||
| 27 | } | ||
| 28 | |||
| 29 | #endif /* __KERNEL__ */ | ||
| 30 | |||
| 31 | #endif /* __IP_SET_BITMAP_H */ | ||
diff --git a/include/linux/netfilter/ipset/ip_set_getport.h b/include/linux/netfilter/ipset/ip_set_getport.h new file mode 100644 index 000000000000..3882a81a3b3c --- /dev/null +++ b/include/linux/netfilter/ipset/ip_set_getport.h | |||
| @@ -0,0 +1,21 @@ | |||
| 1 | #ifndef _IP_SET_GETPORT_H | ||
| 2 | #define _IP_SET_GETPORT_H | ||
| 3 | |||
| 4 | extern bool ip_set_get_ip4_port(const struct sk_buff *skb, bool src, | ||
| 5 | __be16 *port, u8 *proto); | ||
| 6 | |||
| 7 | #if defined(CONFIG_IP6_NF_IPTABLES) || defined(CONFIG_IP6_NF_IPTABLES_MODULE) | ||
| 8 | extern bool ip_set_get_ip6_port(const struct sk_buff *skb, bool src, | ||
| 9 | __be16 *port, u8 *proto); | ||
| 10 | #else | ||
| 11 | static inline bool ip_set_get_ip6_port(const struct sk_buff *skb, bool src, | ||
| 12 | __be16 *port, u8 *proto) | ||
| 13 | { | ||
| 14 | return false; | ||
| 15 | } | ||
| 16 | #endif | ||
| 17 | |||
| 18 | extern bool ip_set_get_ip_port(const struct sk_buff *skb, u8 pf, bool src, | ||
| 19 | __be16 *port); | ||
| 20 | |||
| 21 | #endif /*_IP_SET_GETPORT_H*/ | ||
diff --git a/include/linux/netfilter/ipset/ip_set_hash.h b/include/linux/netfilter/ipset/ip_set_hash.h new file mode 100644 index 000000000000..b86f15c04524 --- /dev/null +++ b/include/linux/netfilter/ipset/ip_set_hash.h | |||
| @@ -0,0 +1,26 @@ | |||
| 1 | #ifndef __IP_SET_HASH_H | ||
| 2 | #define __IP_SET_HASH_H | ||
| 3 | |||
| 4 | /* Hash type specific error codes */ | ||
| 5 | enum { | ||
| 6 | /* Hash is full */ | ||
| 7 | IPSET_ERR_HASH_FULL = IPSET_ERR_TYPE_SPECIFIC, | ||
| 8 | /* Null-valued element */ | ||
| 9 | IPSET_ERR_HASH_ELEM, | ||
| 10 | /* Invalid protocol */ | ||
| 11 | IPSET_ERR_INVALID_PROTO, | ||
| 12 | /* Protocol missing but must be specified */ | ||
| 13 | IPSET_ERR_MISSING_PROTO, | ||
| 14 | }; | ||
| 15 | |||
| 16 | #ifdef __KERNEL__ | ||
| 17 | |||
| 18 | #define IPSET_DEFAULT_HASHSIZE 1024 | ||
| 19 | #define IPSET_MIMINAL_HASHSIZE 64 | ||
| 20 | #define IPSET_DEFAULT_MAXELEM 65536 | ||
| 21 | #define IPSET_DEFAULT_PROBES 4 | ||
| 22 | #define IPSET_DEFAULT_RESIZE 100 | ||
| 23 | |||
| 24 | #endif /* __KERNEL__ */ | ||
| 25 | |||
| 26 | #endif /* __IP_SET_HASH_H */ | ||
diff --git a/include/linux/netfilter/ipset/ip_set_list.h b/include/linux/netfilter/ipset/ip_set_list.h new file mode 100644 index 000000000000..40a63f302613 --- /dev/null +++ b/include/linux/netfilter/ipset/ip_set_list.h | |||
| @@ -0,0 +1,27 @@ | |||
| 1 | #ifndef __IP_SET_LIST_H | ||
| 2 | #define __IP_SET_LIST_H | ||
| 3 | |||
| 4 | /* List type specific error codes */ | ||
| 5 | enum { | ||
| 6 | /* Set name to be added/deleted/tested does not exist. */ | ||
| 7 | IPSET_ERR_NAME = IPSET_ERR_TYPE_SPECIFIC, | ||
| 8 | /* list:set type is not permitted to add */ | ||
| 9 | IPSET_ERR_LOOP, | ||
| 10 | /* Missing reference set */ | ||
| 11 | IPSET_ERR_BEFORE, | ||
| 12 | /* Reference set does not exist */ | ||
| 13 | IPSET_ERR_NAMEREF, | ||
| 14 | /* Set is full */ | ||
| 15 | IPSET_ERR_LIST_FULL, | ||
| 16 | /* Reference set is not added to the set */ | ||
| 17 | IPSET_ERR_REF_EXIST, | ||
| 18 | }; | ||
| 19 | |||
| 20 | #ifdef __KERNEL__ | ||
| 21 | |||
| 22 | #define IP_SET_LIST_DEFAULT_SIZE 8 | ||
| 23 | #define IP_SET_LIST_MIN_SIZE 4 | ||
| 24 | |||
| 25 | #endif /* __KERNEL__ */ | ||
| 26 | |||
| 27 | #endif /* __IP_SET_LIST_H */ | ||
diff --git a/include/linux/netfilter/ipset/ip_set_timeout.h b/include/linux/netfilter/ipset/ip_set_timeout.h new file mode 100644 index 000000000000..9f30c5f2ec1c --- /dev/null +++ b/include/linux/netfilter/ipset/ip_set_timeout.h | |||
| @@ -0,0 +1,127 @@ | |||
| 1 | #ifndef _IP_SET_TIMEOUT_H | ||
| 2 | #define _IP_SET_TIMEOUT_H | ||
| 3 | |||
| 4 | /* Copyright (C) 2003-2011 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu> | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or modify | ||
| 7 | * it under the terms of the GNU General Public License version 2 as | ||
| 8 | * published by the Free Software Foundation. | ||
| 9 | */ | ||
| 10 | |||
| 11 | #ifdef __KERNEL__ | ||
| 12 | |||
| 13 | /* How often should the gc be run by default */ | ||
| 14 | #define IPSET_GC_TIME (3 * 60) | ||
| 15 | |||
| 16 | /* Timeout period depending on the timeout value of the given set */ | ||
| 17 | #define IPSET_GC_PERIOD(timeout) \ | ||
| 18 | ((timeout/3) ? min_t(u32, (timeout)/3, IPSET_GC_TIME) : 1) | ||
| 19 | |||
| 20 | /* Set is defined without timeout support: timeout value may be 0 */ | ||
| 21 | #define IPSET_NO_TIMEOUT UINT_MAX | ||
| 22 | |||
| 23 | #define with_timeout(timeout) ((timeout) != IPSET_NO_TIMEOUT) | ||
| 24 | |||
| 25 | static inline unsigned int | ||
| 26 | ip_set_timeout_uget(struct nlattr *tb) | ||
| 27 | { | ||
| 28 | unsigned int timeout = ip_set_get_h32(tb); | ||
| 29 | |||
| 30 | /* Userspace supplied TIMEOUT parameter: adjust crazy size */ | ||
| 31 | return timeout == IPSET_NO_TIMEOUT ? IPSET_NO_TIMEOUT - 1 : timeout; | ||
| 32 | } | ||
| 33 | |||
| 34 | #ifdef IP_SET_BITMAP_TIMEOUT | ||
| 35 | |||
| 36 | /* Bitmap specific timeout constants and macros for the entries */ | ||
| 37 | |||
| 38 | /* Bitmap entry is unset */ | ||
| 39 | #define IPSET_ELEM_UNSET 0 | ||
| 40 | /* Bitmap entry is set with no timeout value */ | ||
| 41 | #define IPSET_ELEM_PERMANENT (UINT_MAX/2) | ||
| 42 | |||
| 43 | static inline bool | ||
| 44 | ip_set_timeout_test(unsigned long timeout) | ||
| 45 | { | ||
| 46 | return timeout != IPSET_ELEM_UNSET && | ||
| 47 | (timeout == IPSET_ELEM_PERMANENT || | ||
| 48 | time_after(timeout, jiffies)); | ||
| 49 | } | ||
| 50 | |||
| 51 | static inline bool | ||
| 52 | ip_set_timeout_expired(unsigned long timeout) | ||
| 53 | { | ||
| 54 | return timeout != IPSET_ELEM_UNSET && | ||
| 55 | timeout != IPSET_ELEM_PERMANENT && | ||
| 56 | time_before(timeout, jiffies); | ||
| 57 | } | ||
| 58 | |||
| 59 | static inline unsigned long | ||
| 60 | ip_set_timeout_set(u32 timeout) | ||
| 61 | { | ||
| 62 | unsigned long t; | ||
| 63 | |||
| 64 | if (!timeout) | ||
| 65 | return IPSET_ELEM_PERMANENT; | ||
| 66 | |||
| 67 | t = timeout * HZ + jiffies; | ||
| 68 | if (t == IPSET_ELEM_UNSET || t == IPSET_ELEM_PERMANENT) | ||
| 69 | /* Bingo! */ | ||
| 70 | t++; | ||
| 71 | |||
| 72 | return t; | ||
| 73 | } | ||
| 74 | |||
| 75 | static inline u32 | ||
| 76 | ip_set_timeout_get(unsigned long timeout) | ||
| 77 | { | ||
| 78 | return timeout == IPSET_ELEM_PERMANENT ? 0 : (timeout - jiffies)/HZ; | ||
| 79 | } | ||
| 80 | |||
| 81 | #else | ||
| 82 | |||
| 83 | /* Hash specific timeout constants and macros for the entries */ | ||
| 84 | |||
| 85 | /* Hash entry is set with no timeout value */ | ||
| 86 | #define IPSET_ELEM_PERMANENT 0 | ||
| 87 | |||
| 88 | static inline bool | ||
| 89 | ip_set_timeout_test(unsigned long timeout) | ||
| 90 | { | ||
| 91 | return timeout == IPSET_ELEM_PERMANENT || | ||
| 92 | time_after(timeout, jiffies); | ||
| 93 | } | ||
| 94 | |||
| 95 | static inline bool | ||
| 96 | ip_set_timeout_expired(unsigned long timeout) | ||
| 97 | { | ||
| 98 | return timeout != IPSET_ELEM_PERMANENT && | ||
| 99 | time_before(timeout, jiffies); | ||
| 100 | } | ||
| 101 | |||
| 102 | static inline unsigned long | ||
| 103 | ip_set_timeout_set(u32 timeout) | ||
| 104 | { | ||
| 105 | unsigned long t; | ||
| 106 | |||
| 107 | if (!timeout) | ||
| 108 | return IPSET_ELEM_PERMANENT; | ||
| 109 | |||
| 110 | t = timeout * HZ + jiffies; | ||
| 111 | if (t == IPSET_ELEM_PERMANENT) | ||
| 112 | /* Bingo! :-) */ | ||
| 113 | t++; | ||
| 114 | |||
| 115 | return t; | ||
| 116 | } | ||
| 117 | |||
| 118 | static inline u32 | ||
| 119 | ip_set_timeout_get(unsigned long timeout) | ||
| 120 | { | ||
| 121 | return timeout == IPSET_ELEM_PERMANENT ? 0 : (timeout - jiffies)/HZ; | ||
| 122 | } | ||
| 123 | #endif /* ! IP_SET_BITMAP_TIMEOUT */ | ||
| 124 | |||
| 125 | #endif /* __KERNEL__ */ | ||
| 126 | |||
| 127 | #endif /* _IP_SET_TIMEOUT_H */ | ||
diff --git a/include/linux/netfilter/ipset/pfxlen.h b/include/linux/netfilter/ipset/pfxlen.h new file mode 100644 index 000000000000..0e1fb50da562 --- /dev/null +++ b/include/linux/netfilter/ipset/pfxlen.h | |||
| @@ -0,0 +1,35 @@ | |||
| 1 | #ifndef _PFXLEN_H | ||
| 2 | #define _PFXLEN_H | ||
| 3 | |||
| 4 | #include <asm/byteorder.h> | ||
| 5 | #include <linux/netfilter.h> | ||
| 6 | |||
| 7 | /* Prefixlen maps, by Jan Engelhardt */ | ||
| 8 | extern const union nf_inet_addr ip_set_netmask_map[]; | ||
| 9 | extern const union nf_inet_addr ip_set_hostmask_map[]; | ||
| 10 | |||
| 11 | static inline __be32 | ||
| 12 | ip_set_netmask(u8 pfxlen) | ||
| 13 | { | ||
| 14 | return ip_set_netmask_map[pfxlen].ip; | ||
| 15 | } | ||
| 16 | |||
| 17 | static inline const __be32 * | ||
| 18 | ip_set_netmask6(u8 pfxlen) | ||
| 19 | { | ||
| 20 | return &ip_set_netmask_map[pfxlen].ip6[0]; | ||
| 21 | } | ||
| 22 | |||
| 23 | static inline u32 | ||
| 24 | ip_set_hostmask(u8 pfxlen) | ||
| 25 | { | ||
| 26 | return (__force u32) ip_set_hostmask_map[pfxlen].ip; | ||
| 27 | } | ||
| 28 | |||
| 29 | static inline const __be32 * | ||
| 30 | ip_set_hostmask6(u8 pfxlen) | ||
| 31 | { | ||
| 32 | return &ip_set_hostmask_map[pfxlen].ip6[0]; | ||
| 33 | } | ||
| 34 | |||
| 35 | #endif /*_PFXLEN_H */ | ||
diff --git a/include/linux/netfilter/nfnetlink.h b/include/linux/netfilter/nfnetlink.h index 361d6b5630ee..2b11fc1a86be 100644 --- a/include/linux/netfilter/nfnetlink.h +++ b/include/linux/netfilter/nfnetlink.h | |||
| @@ -47,7 +47,8 @@ struct nfgenmsg { | |||
| 47 | #define NFNL_SUBSYS_QUEUE 3 | 47 | #define NFNL_SUBSYS_QUEUE 3 |
| 48 | #define NFNL_SUBSYS_ULOG 4 | 48 | #define NFNL_SUBSYS_ULOG 4 |
| 49 | #define NFNL_SUBSYS_OSF 5 | 49 | #define NFNL_SUBSYS_OSF 5 |
| 50 | #define NFNL_SUBSYS_COUNT 6 | 50 | #define NFNL_SUBSYS_IPSET 6 |
| 51 | #define NFNL_SUBSYS_COUNT 7 | ||
| 51 | 52 | ||
| 52 | #ifdef __KERNEL__ | 53 | #ifdef __KERNEL__ |
| 53 | 54 | ||
diff --git a/include/linux/netfilter/xt_devgroup.h b/include/linux/netfilter/xt_devgroup.h new file mode 100644 index 000000000000..1babde0ec900 --- /dev/null +++ b/include/linux/netfilter/xt_devgroup.h | |||
| @@ -0,0 +1,21 @@ | |||
| 1 | #ifndef _XT_DEVGROUP_H | ||
| 2 | #define _XT_DEVGROUP_H | ||
| 3 | |||
| 4 | #include <linux/types.h> | ||
| 5 | |||
| 6 | enum xt_devgroup_flags { | ||
| 7 | XT_DEVGROUP_MATCH_SRC = 0x1, | ||
| 8 | XT_DEVGROUP_INVERT_SRC = 0x2, | ||
| 9 | XT_DEVGROUP_MATCH_DST = 0x4, | ||
| 10 | XT_DEVGROUP_INVERT_DST = 0x8, | ||
| 11 | }; | ||
| 12 | |||
| 13 | struct xt_devgroup_info { | ||
| 14 | __u32 flags; | ||
| 15 | __u32 src_group; | ||
| 16 | __u32 src_mask; | ||
| 17 | __u32 dst_group; | ||
| 18 | __u32 dst_mask; | ||
| 19 | }; | ||
| 20 | |||
| 21 | #endif /* _XT_DEVGROUP_H */ | ||
diff --git a/include/linux/netfilter/xt_set.h b/include/linux/netfilter/xt_set.h new file mode 100644 index 000000000000..081f1ded2842 --- /dev/null +++ b/include/linux/netfilter/xt_set.h | |||
| @@ -0,0 +1,56 @@ | |||
| 1 | #ifndef _XT_SET_H | ||
| 2 | #define _XT_SET_H | ||
| 3 | |||
| 4 | #include <linux/types.h> | ||
| 5 | #include <linux/netfilter/ipset/ip_set.h> | ||
| 6 | |||
| 7 | /* Revision 0 interface: backward compatible with netfilter/iptables */ | ||
| 8 | |||
| 9 | /* | ||
| 10 | * Option flags for kernel operations (xt_set_info_v0) | ||
| 11 | */ | ||
| 12 | #define IPSET_SRC 0x01 /* Source match/add */ | ||
| 13 | #define IPSET_DST 0x02 /* Destination match/add */ | ||
| 14 | #define IPSET_MATCH_INV 0x04 /* Inverse matching */ | ||
| 15 | |||
| 16 | struct xt_set_info_v0 { | ||
| 17 | ip_set_id_t index; | ||
| 18 | union { | ||
| 19 | __u32 flags[IPSET_DIM_MAX + 1]; | ||
| 20 | struct { | ||
| 21 | __u32 __flags[IPSET_DIM_MAX]; | ||
| 22 | __u8 dim; | ||
| 23 | __u8 flags; | ||
| 24 | } compat; | ||
| 25 | } u; | ||
| 26 | }; | ||
| 27 | |||
| 28 | /* match and target infos */ | ||
| 29 | struct xt_set_info_match_v0 { | ||
| 30 | struct xt_set_info_v0 match_set; | ||
| 31 | }; | ||
| 32 | |||
| 33 | struct xt_set_info_target_v0 { | ||
| 34 | struct xt_set_info_v0 add_set; | ||
| 35 | struct xt_set_info_v0 del_set; | ||
| 36 | }; | ||
| 37 | |||
| 38 | /* Revision 1: current interface to netfilter/iptables */ | ||
| 39 | |||
| 40 | struct xt_set_info { | ||
| 41 | ip_set_id_t index; | ||
| 42 | __u8 dim; | ||
| 43 | __u8 flags; | ||
| 44 | }; | ||
| 45 | |||
| 46 | /* match and target infos */ | ||
| 47 | struct xt_set_info_match { | ||
| 48 | struct xt_set_info match_set; | ||
| 49 | }; | ||
| 50 | |||
| 51 | struct xt_set_info_target { | ||
| 52 | struct xt_set_info add_set; | ||
| 53 | struct xt_set_info del_set; | ||
| 54 | }; | ||
| 55 | |||
| 56 | #endif /*_XT_SET_H*/ | ||
