diff options
Diffstat (limited to 'include/linux/netfilter_ipv4/listhelp.h')
-rw-r--r-- | include/linux/netfilter_ipv4/listhelp.h | 125 |
1 files changed, 125 insertions, 0 deletions
diff --git a/include/linux/netfilter_ipv4/listhelp.h b/include/linux/netfilter_ipv4/listhelp.h new file mode 100644 index 0000000..f2ae7c5 --- /dev/null +++ b/include/linux/netfilter_ipv4/listhelp.h @@ -0,0 +1,125 @@ +#ifndef _LISTHELP_H +#define _LISTHELP_H +#include <linux/config.h> +#include <linux/list.h> +#include <linux/netfilter_ipv4/lockhelp.h> + +/* Header to do more comprehensive job than linux/list.h; assume list + is first entry in structure. */ + +/* Return pointer to first true entry, if any, or NULL. A macro + required to allow inlining of cmpfn. */ +#define LIST_FIND(head, cmpfn, type, args...) \ +({ \ + const struct list_head *__i, *__j = NULL; \ + \ + ASSERT_READ_LOCK(head); \ + list_for_each(__i, (head)) \ + if (cmpfn((const type)__i , ## args)) { \ + __j = __i; \ + break; \ + } \ + (type)__j; \ +}) + +#define LIST_FIND_W(head, cmpfn, type, args...) \ +({ \ + const struct list_head *__i, *__j = NULL; \ + \ + ASSERT_WRITE_LOCK(head); \ + list_for_each(__i, (head)) \ + if (cmpfn((type)__i , ## args)) { \ + __j = __i; \ + break; \ + } \ + (type)__j; \ +}) + +/* Just like LIST_FIND but we search backwards */ +#define LIST_FIND_B(head, cmpfn, type, args...) \ +({ \ + const struct list_head *__i, *__j = NULL; \ + \ + ASSERT_READ_LOCK(head); \ + list_for_each_prev(__i, (head)) \ + if (cmpfn((const type)__i , ## args)) { \ + __j = __i; \ + break; \ + } \ + (type)__j; \ +}) + +static inline int +__list_cmp_same(const void *p1, const void *p2) { return p1 == p2; } + +/* Is this entry in the list? */ +static inline int +list_inlist(struct list_head *head, const void *entry) +{ + return LIST_FIND(head, __list_cmp_same, void *, entry) != NULL; +} + +/* Delete from list. */ +#ifdef CONFIG_NETFILTER_DEBUG +#define LIST_DELETE(head, oldentry) \ +do { \ + ASSERT_WRITE_LOCK(head); \ + if (!list_inlist(head, oldentry)) \ + printk("LIST_DELETE: %s:%u `%s'(%p) not in %s.\n", \ + __FILE__, __LINE__, #oldentry, oldentry, #head); \ + else list_del((struct list_head *)oldentry); \ +} while(0) +#else +#define LIST_DELETE(head, oldentry) list_del((struct list_head *)oldentry) +#endif + +/* Append. */ +static inline void +list_append(struct list_head *head, void *new) +{ + ASSERT_WRITE_LOCK(head); + list_add((new), (head)->prev); +} + +/* Prepend. */ +static inline void +list_prepend(struct list_head *head, void *new) +{ + ASSERT_WRITE_LOCK(head); + list_add(new, head); +} + +/* Insert according to ordering function; insert before first true. */ +#define LIST_INSERT(head, new, cmpfn) \ +do { \ + struct list_head *__i; \ + ASSERT_WRITE_LOCK(head); \ + list_for_each(__i, (head)) \ + if ((new), (typeof (new))__i) \ + break; \ + list_add((struct list_head *)(new), __i->prev); \ +} while(0) + +/* If the field after the list_head is a nul-terminated string, you + can use these functions. */ +static inline int __list_cmp_name(const void *i, const char *name) +{ + return strcmp(name, i+sizeof(struct list_head)) == 0; +} + +/* Returns false if same name already in list, otherwise does insert. */ +static inline int +list_named_insert(struct list_head *head, void *new) +{ + if (LIST_FIND(head, __list_cmp_name, void *, + new + sizeof(struct list_head))) + return 0; + list_prepend(head, new); + return 1; +} + +/* Find this named element in the list. */ +#define list_named_find(head, name) \ +LIST_FIND(head, __list_cmp_name, void *, name) + +#endif /*_LISTHELP_H*/ |