diff options
Diffstat (limited to 'sys/contrib/ipfilter/netinet/ip_pool.c')
-rw-r--r-- | sys/contrib/ipfilter/netinet/ip_pool.c | 1271 |
1 files changed, 884 insertions, 387 deletions
diff --git a/sys/contrib/ipfilter/netinet/ip_pool.c b/sys/contrib/ipfilter/netinet/ip_pool.c index eab3310..2a43cdb 100644 --- a/sys/contrib/ipfilter/netinet/ip_pool.c +++ b/sys/contrib/ipfilter/netinet/ip_pool.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 1993-2001, 2003 by Darren Reed. + * Copyright (C) 2012 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. */ @@ -33,15 +33,10 @@ struct file; # endif #endif #include <sys/time.h> -#if !defined(linux) -# include <sys/protosw.h> -#endif -#include <sys/socket.h> -#if defined(_KERNEL) && (!defined(__SVR4) && !defined(__svr4__)) +#if defined(_KERNEL) && !defined(SOLARIS2) # include <sys/mbuf.h> #endif #if defined(__SVR4) || defined(__svr4__) -# include <sys/filio.h> # include <sys/byteorder.h> # ifdef _KERNEL # include <sys/dditypes.h> @@ -53,69 +48,91 @@ struct file; # include <sys/malloc.h> #endif -#if defined(SOLARIS2) && !defined(_KERNEL) -# include "radix_ipf.h" -#endif -#if defined(_KERNEL) && (defined(__osf__) || defined(AIX) || \ - defined(__hpux) || defined(__sgi)) -# include "radix_ipf_local.h" -# define _RADIX_H_ -#endif +#include <sys/socket.h> #include <net/if.h> #include <netinet/in.h> +#if !defined(_KERNEL) +# include "ipf.h" +#endif #include "netinet/ip_compat.h" #include "netinet/ip_fil.h" #include "netinet/ip_pool.h" - -#if defined(IPFILTER_LOOKUP) && defined(_KERNEL) && \ - ((BSD >= 198911) && !defined(__osf__) && \ - !defined(__hpux) && !defined(__sgi)) -static int rn_freenode __P((struct radix_node *, void *)); -#endif +#include "netinet/radix_ipf.h" /* END OF INCLUDES */ #if !defined(lint) static const char sccsid[] = "@(#)ip_fil.c 2.41 6/5/96 (C) 1993-2000 Darren Reed"; -static const char rcsid[] = "@(#)$Id: ip_pool.c,v 2.55.2.24 2007/10/10 09:45:37 darrenr Exp $"; +static const char rcsid[] = "@(#)$Id$"; #endif -#ifdef IPFILTER_LOOKUP - -# if !defined(RADIX_NODE_HEAD_LOCK) || !defined(RADIX_NODE_HEAD_UNLOCK) || \ - !defined(_KERNEL) -# undef RADIX_NODE_HEAD_LOCK -# undef RADIX_NODE_HEAD_UNLOCK -# define RADIX_NODE_HEAD_LOCK(x) ; -# define RADIX_NODE_HEAD_UNLOCK(x) ; -# endif - -static void ip_pool_clearnodes __P((ip_pool_t *)); -static void *ip_pool_exists __P((int, char *)); - -ip_pool_stat_t ipoolstat; -ipfrwlock_t ip_poolrw; - -/* - * Binary tree routines from Sedgewick and enhanced to do ranges of addresses. - * NOTE: Insertion *MUST* be from greatest range to least for it to work! - * These should be replaced, eventually, by something else - most notably a - * interval searching method. The important feature is to be able to find - * the best match. - * - * So why not use a radix tree for this? As the first line implies, it - * has been written to work with a _range_ of addresses. A range is not - * necessarily a match with any given netmask so what we end up dealing - * with is an interval tree. Implementations of these are hard to find - * and the one herein is far from bug free. - * - * Sigh, in the end I became convinced that the bugs the code contained did - * not make it worthwhile not using radix trees. For now the radix tree from - * 4.4 BSD is used, but this is not viewed as a long term solution. - */ -ip_pool_t *ip_pool_list[IPL_LOGSIZE] = { NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL }; +typedef struct ipf_pool_softc_s { + void *ipf_radix; + ip_pool_t *ipf_pool_list[LOOKUP_POOL_SZ]; + ipf_pool_stat_t ipf_pool_stats; + ip_pool_node_t *ipf_node_explist; +} ipf_pool_softc_t; + + +static void ipf_pool_clearnodes __P((ipf_main_softc_t *, ipf_pool_softc_t *, + ip_pool_t *)); +static int ipf_pool_create __P((ipf_main_softc_t *, ipf_pool_softc_t *, iplookupop_t *)); +static int ipf_pool_deref __P((ipf_main_softc_t *, void *, void *)); +static int ipf_pool_destroy __P((ipf_main_softc_t *, ipf_pool_softc_t *, int, char *)); +static void *ipf_pool_exists __P((ipf_pool_softc_t *, int, char *)); +static void *ipf_pool_find __P((void *, int, char *)); +static ip_pool_node_t *ipf_pool_findeq __P((ipf_pool_softc_t *, ip_pool_t *, + addrfamily_t *, addrfamily_t *)); +static void ipf_pool_free __P((ipf_main_softc_t *, ipf_pool_softc_t *, + ip_pool_t *)); +static int ipf_pool_insert_node __P((ipf_main_softc_t *, ipf_pool_softc_t *, + ip_pool_t *, struct ip_pool_node *)); +static int ipf_pool_iter_deref __P((ipf_main_softc_t *, void *, int, int, void *)); +static int ipf_pool_iter_next __P((ipf_main_softc_t *, void *, ipftoken_t *, + ipflookupiter_t *)); +static size_t ipf_pool_flush __P((ipf_main_softc_t *, void *, iplookupflush_t *)); +static int ipf_pool_node_add __P((ipf_main_softc_t *, void *, iplookupop_t *, + int)); +static int ipf_pool_node_del __P((ipf_main_softc_t *, void *, iplookupop_t *, + int)); +static void ipf_pool_node_deref __P((ipf_pool_softc_t *, ip_pool_node_t *)); +static int ipf_pool_remove_node __P((ipf_main_softc_t *, ipf_pool_softc_t *, + ip_pool_t *, ip_pool_node_t *)); +static int ipf_pool_search __P((ipf_main_softc_t *, void *, int, + void *, u_int)); +static void *ipf_pool_soft_create __P((ipf_main_softc_t *)); +static void ipf_pool_soft_destroy __P((ipf_main_softc_t *, void *)); +static void ipf_pool_soft_fini __P((ipf_main_softc_t *, void *)); +static int ipf_pool_soft_init __P((ipf_main_softc_t *, void *)); +static int ipf_pool_stats_get __P((ipf_main_softc_t *, void *, iplookupop_t *)); +static int ipf_pool_table_add __P((ipf_main_softc_t *, void *, iplookupop_t *)); +static int ipf_pool_table_del __P((ipf_main_softc_t *, void *, iplookupop_t *)); +static void *ipf_pool_select_add_ref __P((void *, int, char *)); +static void ipf_pool_expire __P((ipf_main_softc_t *, void *)); + +ipf_lookup_t ipf_pool_backend = { + IPLT_POOL, + ipf_pool_soft_create, + ipf_pool_soft_destroy, + ipf_pool_soft_init, + ipf_pool_soft_fini, + ipf_pool_search, + ipf_pool_flush, + ipf_pool_iter_deref, + ipf_pool_iter_next, + ipf_pool_node_add, + ipf_pool_node_del, + ipf_pool_stats_get, + ipf_pool_table_add, + ipf_pool_table_del, + ipf_pool_deref, + ipf_pool_find, + ipf_pool_select_add_ref, + NULL, + ipf_pool_expire, + NULL +}; #ifdef TEST_POOL @@ -126,96 +143,98 @@ main(argc, argv) int argc; char *argv[]; { + ip_pool_node_t node; addrfamily_t a, b; iplookupop_t op; ip_pool_t *ipo; i6addr_t ip; - RWLOCK_INIT(&ip_poolrw, "poolrw"); - ip_pool_init(); + RWLOCK_INIT(softc->ipf_poolrw, "poolrw"); + ipf_pool_init(); - bzero((char *)&a, sizeof(a)); - bzero((char *)&b, sizeof(b)); bzero((char *)&ip, sizeof(ip)); bzero((char *)&op, sizeof(op)); + bzero((char *)&node, sizeof(node)); strcpy(op.iplo_name, "0"); - if (ip_pool_create(&op) == 0) - ipo = ip_pool_exists(0, "0"); - - a.adf_addr.in4.s_addr = 0x0a010203; - b.adf_addr.in4.s_addr = 0xffffffff; - ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 1); - ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 1); - - a.adf_addr.in4.s_addr = 0x0a000000; - b.adf_addr.in4.s_addr = 0xff000000; - ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 0); - ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 0); - - a.adf_addr.in4.s_addr = 0x0a010100; - b.adf_addr.in4.s_addr = 0xffffff00; - ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 1); - ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 1); - - a.adf_addr.in4.s_addr = 0x0a010200; - b.adf_addr.in4.s_addr = 0xffffff00; - ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 0); - ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 0); - - a.adf_addr.in4.s_addr = 0x0a010000; - b.adf_addr.in4.s_addr = 0xffff0000; - ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 1); - ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 1); - - a.adf_addr.in4.s_addr = 0x0a01020f; - b.adf_addr.in4.s_addr = 0xffffffff; - ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 1); - ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 1); + if (ipf_pool_create(&op) == 0) + ipo = ipf_pool_exists(0, "0"); + + node.ipn_addr.adf_family = AF_INET; + + node.ipn_addr.adf_addr.in4.s_addr = 0x0a010203; + node.ipn_mask.adf_addr.in4.s_addr = 0xffffffff; + node.ipn_info = 1; + ipf_pool_insert_node(ipo, &node); + + node.ipn_addr.adf_addr.in4.s_addr = 0x0a000000; + node.ipn_mask.adf_addr.in4.s_addr = 0xff000000; + node.ipn_info = 0; + ipf_pool_insert_node(ipo, &node); + + node.ipn_addr.adf_addr.in4.s_addr = 0x0a010100; + node.ipn_mask.adf_addr.in4.s_addr = 0xffffff00; + node.ipn_info = 1; + ipf_pool_insert_node(ipo, &node); + + node.ipn_addr.adf_addr.in4.s_addr = 0x0a010200; + node.ipn_mask.adf_addr.in4.s_addr = 0xffffff00; + node.ipn_info = 0; + ipf_pool_insert_node(ipo, &node); + + node.ipn_addr.adf_addr.in4.s_addr = 0x0a010000; + node.ipn_mask.adf_addr.in4.s_addr = 0xffff0000; + node.ipn_info = 1; + ipf_pool_insert_node(ipo, &node); + + node.ipn_addr.adf_addr.in4.s_addr = 0x0a01020f; + node.ipn_mask.adf_addr.in4.s_addr = 0xffffffff; + node.ipn_info = 1; + ipf_pool_insert_node(ipo, &node); #ifdef DEBUG_POOL -treeprint(ipo); + treeprint(ipo); #endif ip.in4.s_addr = 0x0a00aabb; printf("search(%#x) = %d (0)\n", ip.in4.s_addr, - ip_pool_search(ipo, 4, &ip)); + ipf_pool_search(ipo, 4, &ip, 1)); ip.in4.s_addr = 0x0a000001; printf("search(%#x) = %d (0)\n", ip.in4.s_addr, - ip_pool_search(ipo, 4, &ip)); + ipf_pool_search(ipo, 4, &ip, 1)); ip.in4.s_addr = 0x0a000101; printf("search(%#x) = %d (0)\n", ip.in4.s_addr, - ip_pool_search(ipo, 4, &ip)); + ipf_pool_search(ipo, 4, &ip, 1)); ip.in4.s_addr = 0x0a010001; printf("search(%#x) = %d (1)\n", ip.in4.s_addr, - ip_pool_search(ipo, 4, &ip)); + ipf_pool_search(ipo, 4, &ip, 1)); ip.in4.s_addr = 0x0a010101; printf("search(%#x) = %d (1)\n", ip.in4.s_addr, - ip_pool_search(ipo, 4, &ip)); + ipf_pool_search(ipo, 4, &ip, 1)); ip.in4.s_addr = 0x0a010201; printf("search(%#x) = %d (0)\n", ip.in4.s_addr, - ip_pool_search(ipo, 4, &ip)); + ipf_pool_search(ipo, 4, &ip, 1)); ip.in4.s_addr = 0x0a010203; printf("search(%#x) = %d (1)\n", ip.in4.s_addr, - ip_pool_search(ipo, 4, &ip)); + ipf_pool_search(ipo, 4, &ip, 1)); ip.in4.s_addr = 0x0a01020f; printf("search(%#x) = %d (1)\n", ip.in4.s_addr, - ip_pool_search(ipo, 4, &ip)); + ipf_pool_search(ipo, 4, &ip, 1)); ip.in4.s_addr = 0x0b00aabb; printf("search(%#x) = %d (-1)\n", ip.in4.s_addr, - ip_pool_search(ipo, 4, &ip)); + ipf_pool_search(ipo, 4, &ip, 1)); #ifdef DEBUG_POOL -treeprint(ipo); + treeprint(ipo); #endif - ip_pool_fini(); + ipf_pool_fini(); return 0; } @@ -223,7 +242,7 @@ treeprint(ipo); void treeprint(ipo) -ip_pool_t *ipo; + ip_pool_t *ipo; { ip_pool_node_t *c; @@ -237,123 +256,445 @@ ip_pool_t *ipo; /* ------------------------------------------------------------------------ */ -/* Function: ip_pool_init */ +/* Function: ipf_pool_soft_create */ +/* Returns: void * - NULL = failure, else pointer to local context */ +/* Parameters: softc(I) - pointer to soft context main structure */ +/* */ +/* Initialise the routing table data structures where required. */ +/* ------------------------------------------------------------------------ */ +static void * +ipf_pool_soft_create(softc) + ipf_main_softc_t *softc; +{ + ipf_pool_softc_t *softp; + + KMALLOC(softp, ipf_pool_softc_t *); + if (softp == NULL) { + IPFERROR(70032); + return NULL; + } + + bzero((char *)softp, sizeof(*softp)); + + softp->ipf_radix = ipf_rx_create(); + if (softp->ipf_radix == NULL) { + IPFERROR(70033); + KFREE(softp); + return NULL; + } + + return softp; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: ipf_pool_soft_init */ /* Returns: int - 0 = success, else error */ +/* Parameters: softc(I) - pointer to soft context main structure */ +/* arg(I) - pointer to local context to use */ /* */ /* Initialise the routing table data structures where required. */ /* ------------------------------------------------------------------------ */ -int ip_pool_init() +static int +ipf_pool_soft_init(softc, arg) + ipf_main_softc_t *softc; + void *arg; { + ipf_pool_softc_t *softp = arg; - bzero((char *)&ipoolstat, sizeof(ipoolstat)); + ipf_rx_init(softp->ipf_radix); -#if (!defined(_KERNEL) || (BSD < 199306)) - rn_init(); -#endif return 0; } /* ------------------------------------------------------------------------ */ -/* Function: ip_pool_fini */ -/* Returns: int - 0 = success, else error */ +/* Function: ipf_pool_soft_fini */ +/* Returns: Nil */ +/* Parameters: softc(I) - pointer to soft context main structure */ +/* arg(I) - pointer to local context to use */ /* Locks: WRITE(ipf_global) */ /* */ /* Clean up all the pool data structures allocated and call the cleanup */ -/* function for the radix tree that supports the pools. ip_pool_destroy() is*/ +/* function for the radix tree that supports the pools. ipf_pool_destroy is */ /* used to delete the pools one by one to ensure they're properly freed up. */ /* ------------------------------------------------------------------------ */ -void ip_pool_fini() +static void +ipf_pool_soft_fini(softc, arg) + ipf_main_softc_t *softc; + void *arg; { + ipf_pool_softc_t *softp = arg; ip_pool_t *p, *q; int i; - for (i = 0; i <= IPL_LOGMAX; i++) { - for (q = ip_pool_list[i]; (p = q) != NULL; ) { + softc = arg; + + for (i = -1; i <= IPL_LOGMAX; i++) { + for (q = softp->ipf_pool_list[i + 1]; (p = q) != NULL; ) { q = p->ipo_next; - (void) ip_pool_destroy(i, p->ipo_name); + (void) ipf_pool_destroy(softc, arg, i, p->ipo_name); } } +} + + +/* ------------------------------------------------------------------------ */ +/* Function: ipf_pool_soft_destroy */ +/* Returns: Nil */ +/* Parameters: softc(I) - pointer to soft context main structure */ +/* arg(I) - pointer to local context to use */ +/* */ +/* Clean up the pool by free'ing the radix tree associated with it and free */ +/* up the pool context too. */ +/* ------------------------------------------------------------------------ */ +static void +ipf_pool_soft_destroy(softc, arg) + ipf_main_softc_t *softc; + void *arg; +{ + ipf_pool_softc_t *softp = arg; + + ipf_rx_destroy(softp->ipf_radix); + + KFREE(softp); +} + + +/* ------------------------------------------------------------------------ */ +/* Function: ipf_pool_node_add */ +/* Returns: int - 0 = success, else error */ +/* Parameters: softc(I) - pointer to soft context main structure */ +/* arg(I) - pointer to local context to use */ +/* op(I) - pointer to lookup operatin data */ +/* */ +/* When adding a new node, a check is made to ensure that the address/mask */ +/* pair supplied has been appropriately prepared by applying the mask to */ +/* the address prior to calling for the pair to be added. */ +/* ------------------------------------------------------------------------ */ +static int +ipf_pool_node_add(softc, arg, op, uid) + ipf_main_softc_t *softc; + void *arg; + iplookupop_t *op; + int uid; +{ + ip_pool_node_t node, *m; + ip_pool_t *p; + int err; -#if (!defined(_KERNEL) || (BSD < 199306)) - rn_fini(); + if (op->iplo_size != sizeof(node)) { + IPFERROR(70014); + return EINVAL; + } + + err = COPYIN(op->iplo_struct, &node, sizeof(node)); + if (err != 0) { + IPFERROR(70015); + return EFAULT; + } + + p = ipf_pool_find(arg, op->iplo_unit, op->iplo_name); + if (p == NULL) { + IPFERROR(70017); + return ESRCH; + } + + if (node.ipn_addr.adf_family == AF_INET) { + if (node.ipn_addr.adf_len != offsetof(addrfamily_t, adf_addr) + + sizeof(struct in_addr)) { + IPFERROR(70028); + return EINVAL; + } + } +#ifdef USE_INET6 + else if (node.ipn_addr.adf_family == AF_INET6) { + if (node.ipn_addr.adf_len != offsetof(addrfamily_t, adf_addr) + + sizeof(struct in6_addr)) { + IPFERROR(70034); + return EINVAL; + } + } +#endif + if (node.ipn_mask.adf_len != node.ipn_addr.adf_len) { + IPFERROR(70029); + return EINVAL; + } + + /* + * Check that the address/mask pair works. + */ + if (node.ipn_addr.adf_family == AF_INET) { + if ((node.ipn_addr.adf_addr.in4.s_addr & + node.ipn_mask.adf_addr.in4.s_addr) != + node.ipn_addr.adf_addr.in4.s_addr) { + IPFERROR(70035); + return EINVAL; + } + } +#ifdef USE_INET6 + else if (node.ipn_addr.adf_family == AF_INET6) { + if (IP6_MASKNEQ(&node.ipn_addr.adf_addr.in6, + &node.ipn_mask.adf_addr.in6, + &node.ipn_addr.adf_addr.in6)) { + IPFERROR(70036); + return EINVAL; + } + } #endif + + /* + * add an entry to a pool - return an error if it already + * exists remove an entry from a pool - if it exists + * - in both cases, the pool *must* exist! + */ + m = ipf_pool_findeq(arg, p, &node.ipn_addr, &node.ipn_mask); + if (m != NULL) { + IPFERROR(70018); + return EEXIST; + } + err = ipf_pool_insert_node(softc, arg, p, &node); + + return err; } /* ------------------------------------------------------------------------ */ -/* Function: ip_pool_statistics */ -/* Returns: int - 0 = success, else error */ -/* Parameters: op(I) - pointer to lookup operation arguments */ +/* Function: ipf_pool_node_del */ +/* Returns: int - 0 = success, else error */ +/* Parameters: softc(I) - pointer to soft context main structure */ +/* arg(I) - pointer to local context to use */ +/* op(I) - pointer to lookup operatin data */ +/* */ +/* ------------------------------------------------------------------------ */ +static int +ipf_pool_node_del(softc, arg, op, uid) + ipf_main_softc_t *softc; + void *arg; + iplookupop_t *op; + int uid; +{ + ip_pool_node_t node, *m; + ip_pool_t *p; + int err; + + + if (op->iplo_size != sizeof(node)) { + IPFERROR(70019); + return EINVAL; + } + node.ipn_uid = uid; + + err = COPYIN(op->iplo_struct, &node, sizeof(node)); + if (err != 0) { + IPFERROR(70020); + return EFAULT; + } + + if (node.ipn_addr.adf_family == AF_INET) { + if (node.ipn_addr.adf_len != offsetof(addrfamily_t, adf_addr) + + sizeof(struct in_addr)) { + IPFERROR(70030); + return EINVAL; + } + } +#ifdef USE_INET6 + else if (node.ipn_addr.adf_family == AF_INET6) { + if (node.ipn_addr.adf_len != offsetof(addrfamily_t, adf_addr) + + sizeof(struct in6_addr)) { + IPFERROR(70037); + return EINVAL; + } + } +#endif + if (node.ipn_mask.adf_len != node.ipn_addr.adf_len) { + IPFERROR(70031); + return EINVAL; + } + + p = ipf_pool_find(arg, op->iplo_unit, op->iplo_name); + if (p == NULL) { + IPFERROR(70021); + return ESRCH; + } + + m = ipf_pool_findeq(arg, p, &node.ipn_addr, &node.ipn_mask); + if (m == NULL) { + IPFERROR(70022); + return ENOENT; + } + + if ((uid != 0) && (uid != m->ipn_uid)) { + IPFERROR(70024); + return EACCES; + } + + err = ipf_pool_remove_node(softc, arg, p, m); + + return err; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: ipf_pool_table_add */ +/* Returns: int - 0 = success, else error */ +/* Parameters: softc(I) - pointer to soft context main structure */ +/* arg(I) - pointer to local context to use */ +/* op(I) - pointer to lookup operatin data */ +/* */ +/* ------------------------------------------------------------------------ */ +static int +ipf_pool_table_add(softc, arg, op) + ipf_main_softc_t *softc; + void *arg; + iplookupop_t *op; +{ + int err; + + if (((op->iplo_arg & LOOKUP_ANON) == 0) && + (ipf_pool_find(arg, op->iplo_unit, op->iplo_name) != NULL)) { + IPFERROR(70023); + err = EEXIST; + } else { + err = ipf_pool_create(softc, arg, op); + } + + return err; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: ipf_pool_table_del */ +/* Returns: int - 0 = success, else error */ +/* Parameters: softc(I) - pointer to soft context main structure */ +/* arg(I) - pointer to local context to use */ +/* op(I) - pointer to lookup operatin data */ +/* */ +/* ------------------------------------------------------------------------ */ +static int +ipf_pool_table_del(softc, arg, op) + ipf_main_softc_t *softc; + void *arg; + iplookupop_t *op; +{ + return ipf_pool_destroy(softc, arg, op->iplo_unit, op->iplo_name); +} + + +/* ------------------------------------------------------------------------ */ +/* Function: ipf_pool_statistics */ +/* Returns: int - 0 = success, else error */ +/* Parameters: softc(I) - pointer to soft context main structure */ +/* arg(I) - pointer to local context to use */ +/* op(I) - pointer to lookup operatin data */ /* */ /* Copy the current statistics out into user space, collecting pool list */ /* pointers as appropriate for later use. */ /* ------------------------------------------------------------------------ */ -int ip_pool_statistics(op) -iplookupop_t *op; +static int +ipf_pool_stats_get(softc, arg, op) + ipf_main_softc_t *softc; + void *arg; + iplookupop_t *op; { - ip_pool_stat_t stats; + ipf_pool_softc_t *softp = arg; + ipf_pool_stat_t stats; int unit, i, err = 0; - if (op->iplo_size != sizeof(ipoolstat)) + if (op->iplo_size != sizeof(ipf_pool_stat_t)) { + IPFERROR(70001); return EINVAL; + } - bcopy((char *)&ipoolstat, (char *)&stats, sizeof(stats)); + bcopy((char *)&softp->ipf_pool_stats, (char *)&stats, sizeof(stats)); unit = op->iplo_unit; if (unit == IPL_LOGALL) { - for (i = 0; i < IPL_LOGSIZE; i++) - stats.ipls_list[i] = ip_pool_list[i]; - } else if (unit >= 0 && unit < IPL_LOGSIZE) { + for (i = 0; i <= LOOKUP_POOL_MAX; i++) + stats.ipls_list[i] = softp->ipf_pool_list[i]; + } else if (unit >= 0 && unit <= IPL_LOGMAX) { + unit++; /* -1 => 0 */ if (op->iplo_name[0] != '\0') - stats.ipls_list[unit] = ip_pool_exists(unit, - op->iplo_name); + stats.ipls_list[unit] = ipf_pool_exists(softp, unit - 1, + op->iplo_name); else - stats.ipls_list[unit] = ip_pool_list[unit]; - } else + stats.ipls_list[unit] = softp->ipf_pool_list[unit]; + } else { + IPFERROR(70025); err = EINVAL; - if (err == 0) + } + if (err == 0) { err = COPYOUT(&stats, op->iplo_struct, sizeof(stats)); - return err; + if (err != 0) { + IPFERROR(70026); + return EFAULT; + } + } + return 0; } /* ------------------------------------------------------------------------ */ -/* Function: ip_pool_exists */ -/* Returns: int - 0 = success, else error */ -/* Parameters: ipo(I) - pointer to the pool getting the new node. */ +/* Function: ipf_pool_exists */ +/* Returns: int - 0 = success, else error */ +/* Parameters: softp(I) - pointer to soft context pool information */ +/* unit(I) - ipfilter device to which we are working on */ +/* name(I) - name of the pool */ /* */ /* Find a matching pool inside the collection of pools for a particular */ /* device, indicated by the unit number. */ /* ------------------------------------------------------------------------ */ -static void *ip_pool_exists(unit, name) -int unit; -char *name; +static void * +ipf_pool_exists(softp, unit, name) + ipf_pool_softc_t *softp; + int unit; + char *name; { ip_pool_t *p; + int i; - for (p = ip_pool_list[unit]; p != NULL; p = p->ipo_next) - if (strncmp(p->ipo_name, name, sizeof(p->ipo_name)) == 0) - break; + if (unit == IPL_LOGALL) { + for (i = 0; i <= LOOKUP_POOL_MAX; i++) { + for (p = softp->ipf_pool_list[i]; p != NULL; + p = p->ipo_next) { + if (strncmp(p->ipo_name, name, + sizeof(p->ipo_name)) == 0) + break; + } + if (p != NULL) + break; + } + } else { + for (p = softp->ipf_pool_list[unit + 1]; p != NULL; + p = p->ipo_next) + if (strncmp(p->ipo_name, name, + sizeof(p->ipo_name)) == 0) + break; + } return p; } /* ------------------------------------------------------------------------ */ -/* Function: ip_pool_find */ -/* Returns: int - 0 = success, else error */ -/* Parameters: ipo(I) - pointer to the pool getting the new node. */ +/* Function: ipf_pool_find */ +/* Returns: int - 0 = success, else error */ +/* Parameters: arg(I) - pointer to local context to use */ +/* unit(I) - ipfilter device to which we are working on */ +/* name(I) - name of the pool */ /* */ /* Find a matching pool inside the collection of pools for a particular */ /* device, indicated by the unit number. If it is marked for deletion then */ /* pretend it does not exist. */ /* ------------------------------------------------------------------------ */ -void *ip_pool_find(unit, name) -int unit; -char *name; +static void * +ipf_pool_find(arg, unit, name) + void *arg; + int unit; + char *name; { + ipf_pool_softc_t *softp = arg; ip_pool_t *p; - p = ip_pool_exists(unit, name); + p = ipf_pool_exists(softp, unit, name); if ((p != NULL) && (p->ipo_flags & IPOOL_DELETE)) return NULL; @@ -362,45 +703,75 @@ char *name; /* ------------------------------------------------------------------------ */ -/* Function: ip_pool_findeq */ +/* Function: ipf_pool_select_add_ref */ +/* Returns: int - 0 = success, else error */ +/* Parameters: arg(I) - pointer to local context to use */ +/* unit(I) - ipfilter device to which we are working on */ +/* name(I) - name of the pool */ +/* */ +/* ------------------------------------------------------------------------ */ +static void * +ipf_pool_select_add_ref(arg, unit, name) + void *arg; + int unit; + char *name; +{ + ip_pool_t *p; + + p = ipf_pool_find(arg, -1, name); + if (p == NULL) + p = ipf_pool_find(arg, unit, name); + if (p != NULL) { + ATOMIC_INC32(p->ipo_ref); + } + return p; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: ipf_pool_findeq */ /* Returns: int - 0 = success, else error */ -/* Parameters: ipo(I) - pointer to the pool getting the new node. */ -/* addr(I) - pointer to address information to delete */ -/* mask(I) - */ +/* Parameters: softp(I) - pointer to soft context pool information */ +/* ipo(I) - pointer to the pool getting the new node. */ +/* addr(I) - pointer to address information to match on */ +/* mask(I) - pointer to the address mask to match */ /* */ /* Searches for an exact match of an entry in the pool. */ /* ------------------------------------------------------------------------ */ -ip_pool_node_t *ip_pool_findeq(ipo, addr, mask) -ip_pool_t *ipo; -addrfamily_t *addr, *mask; +extern void printhostmask __P((int, u_32_t *, u_32_t *)); +static ip_pool_node_t * +ipf_pool_findeq(softp, ipo, addr, mask) + ipf_pool_softc_t *softp; + ip_pool_t *ipo; + addrfamily_t *addr, *mask; { - struct radix_node *n; - SPL_INT(s); - - SPL_NET(s); - RADIX_NODE_HEAD_LOCK(ipo->ipo_head); - n = ipo->ipo_head->rnh_lookup(addr, mask, ipo->ipo_head); - RADIX_NODE_HEAD_UNLOCK(ipo->ipo_head); - SPL_X(s); + ipf_rdx_node_t *n; + + n = ipo->ipo_head->lookup(ipo->ipo_head, addr, mask); return (ip_pool_node_t *)n; } /* ------------------------------------------------------------------------ */ -/* Function: ip_pool_search */ +/* Function: ipf_pool_search */ /* Returns: int - 0 == +ve match, -1 == error, 1 == -ve/no match */ -/* Parameters: tptr(I) - pointer to the pool to search */ +/* Parameters: softc(I) - pointer to soft context main structure */ +/* tptr(I) - pointer to the pool to search */ /* version(I) - IP protocol version (4 or 6) */ /* dptr(I) - pointer to address information */ +/* bytes(I) - length of packet */ /* */ /* Search the pool for a given address and return a search result. */ /* ------------------------------------------------------------------------ */ -int ip_pool_search(tptr, ipversion, dptr) -void *tptr; -int ipversion; -void *dptr; +static int +ipf_pool_search(softc, tptr, ipversion, dptr, bytes) + ipf_main_softc_t *softc; + void *tptr; + int ipversion; + void *dptr; + u_int bytes; { - struct radix_node *rn; + ipf_rdx_node_t *rn; ip_pool_node_t *m; i6addr_t *addr; addrfamily_t v; @@ -415,102 +786,154 @@ void *dptr; m = NULL; addr = (i6addr_t *)dptr; bzero(&v, sizeof(v)); - v.adf_len = offsetof(addrfamily_t, adf_addr); if (ipversion == 4) { - v.adf_len += sizeof(addr->in4); + v.adf_family = AF_INET; + v.adf_len = offsetof(addrfamily_t, adf_addr) + + sizeof(struct in_addr); v.adf_addr.in4 = addr->in4; #ifdef USE_INET6 } else if (ipversion == 6) { - v.adf_len += sizeof(addr->in6); + v.adf_family = AF_INET6; + v.adf_len = offsetof(addrfamily_t, adf_addr) + + sizeof(struct in6_addr); v.adf_addr.in6 = addr->in6; #endif } else return -1; - READ_ENTER(&ip_poolrw); + READ_ENTER(&softc->ipf_poolrw); - RADIX_NODE_HEAD_LOCK(ipo->ipo_head); - rn = ipo->ipo_head->rnh_matchaddr(&v, ipo->ipo_head); - RADIX_NODE_HEAD_UNLOCK(ipo->ipo_head); + rn = ipo->ipo_head->matchaddr(ipo->ipo_head, &v); - if ((rn != NULL) && ((rn->rn_flags & RNF_ROOT) == 0)) { + if ((rn != NULL) && (rn->root == 0)) { m = (ip_pool_node_t *)rn; ipo->ipo_hits++; + m->ipn_bytes += bytes; m->ipn_hits++; rv = m->ipn_info; } - RWLOCK_EXIT(&ip_poolrw); + RWLOCK_EXIT(&softc->ipf_poolrw); return rv; } /* ------------------------------------------------------------------------ */ -/* Function: ip_pool_insert */ -/* Returns: int - 0 = success, else error */ -/* Parameters: ipo(I) - pointer to the pool getting the new node. */ -/* addr(I) - address being added as a node */ -/* mask(I) - netmask to with the node being added */ -/* info(I) - extra information to store in this node. */ -/* Locks: WRITE(ip_poolrw) */ +/* Function: ipf_pool_insert_node */ +/* Returns: int - 0 = success, else error */ +/* Parameters: softc(I) - pointer to soft context main structure */ +/* softp(I) - pointer to soft context pool information */ +/* ipo(I) - pointer to the pool getting the new node. */ +/* node(I) - structure with address/mask to add */ +/* Locks: WRITE(ipf_poolrw) */ /* */ /* Add another node to the pool given by ipo. The three parameters passed */ /* in (addr, mask, info) shold all be stored in the node. */ /* ------------------------------------------------------------------------ */ -int ip_pool_insert(ipo, addr, mask, info) -ip_pool_t *ipo; -i6addr_t *addr, *mask; -int info; +static int +ipf_pool_insert_node(softc, softp, ipo, node) + ipf_main_softc_t *softc; + ipf_pool_softc_t *softp; + ip_pool_t *ipo; + struct ip_pool_node *node; { - struct radix_node *rn; + ipf_rdx_node_t *rn; ip_pool_node_t *x; + if ((node->ipn_addr.adf_len > sizeof(*rn)) || + (node->ipn_addr.adf_len < 4)) { + IPFERROR(70003); + return EINVAL; + } + + if ((node->ipn_mask.adf_len > sizeof(*rn)) || + (node->ipn_mask.adf_len < 4)) { + IPFERROR(70004); + return EINVAL; + } + KMALLOC(x, ip_pool_node_t *); if (x == NULL) { + IPFERROR(70002); return ENOMEM; } - bzero(x, sizeof(*x)); - - x->ipn_info = info; - (void)strncpy(x->ipn_name, ipo->ipo_name, sizeof(x->ipn_name)); + *x = *node; + bzero((char *)x->ipn_nodes, sizeof(x->ipn_nodes)); + x->ipn_owner = ipo; + x->ipn_hits = 0; + x->ipn_next = NULL; + x->ipn_pnext = NULL; + x->ipn_dnext = NULL; + x->ipn_pdnext = NULL; + + if (x->ipn_die != 0) { + /* + * If the new node has a given expiration time, insert it + * into the list of expiring nodes with the ones to be + * removed first added to the front of the list. The + * insertion is O(n) but it is kept sorted for quick scans + * at expiration interval checks. + */ + ip_pool_node_t *n; + + x->ipn_die = softc->ipf_ticks + IPF_TTLVAL(x->ipn_die); + for (n = softp->ipf_node_explist; n != NULL; n = n->ipn_dnext) { + if (x->ipn_die < n->ipn_die) + break; + if (n->ipn_dnext == NULL) { + /* + * We've got to the last node and everything + * wanted to be expired before this new node, + * so we have to tack it on the end... + */ + n->ipn_dnext = x; + x->ipn_pdnext = &n->ipn_dnext; + n = NULL; + break; + } + } - bcopy(addr, &x->ipn_addr.adf_addr, sizeof(*addr)); - x->ipn_addr.adf_len = sizeof(x->ipn_addr); - bcopy(mask, &x->ipn_mask.adf_addr, sizeof(*mask)); - x->ipn_mask.adf_len = sizeof(x->ipn_mask); + if (softp->ipf_node_explist == NULL) { + softp->ipf_node_explist = x; + x->ipn_pdnext = &softp->ipf_node_explist; + } else if (n != NULL) { + x->ipn_dnext = n; + x->ipn_pdnext = n->ipn_pdnext; + n->ipn_pdnext = &x->ipn_dnext; + } + } - RADIX_NODE_HEAD_LOCK(ipo->ipo_head); - rn = ipo->ipo_head->rnh_addaddr(&x->ipn_addr, &x->ipn_mask, - ipo->ipo_head, x->ipn_nodes); - RADIX_NODE_HEAD_UNLOCK(ipo->ipo_head); + rn = ipo->ipo_head->addaddr(ipo->ipo_head, &x->ipn_addr, &x->ipn_mask, + x->ipn_nodes); #ifdef DEBUG_POOL printf("Added %p at %p\n", x, rn); #endif if (rn == NULL) { KFREE(x); + IPFERROR(70005); return ENOMEM; } x->ipn_ref = 1; - x->ipn_next = ipo->ipo_list; - x->ipn_pnext = &ipo->ipo_list; - if (ipo->ipo_list != NULL) - ipo->ipo_list->ipn_pnext = &x->ipn_next; - ipo->ipo_list = x; + x->ipn_pnext = ipo->ipo_tail; + *ipo->ipo_tail = x; + ipo->ipo_tail = &x->ipn_next; - ipoolstat.ipls_nodes++; + softp->ipf_pool_stats.ipls_nodes++; return 0; } /* ------------------------------------------------------------------------ */ -/* Function: ip_pool_create */ -/* Returns: int - 0 = success, else error */ -/* Parameters: op(I) - pointer to iplookup struct with call details */ -/* Locks: WRITE(ip_poolrw) */ +/* Function: ipf_pool_create */ +/* Returns: int - 0 = success, else error */ +/* Parameters: softc(I) - pointer to soft context main structure */ +/* softp(I) - pointer to soft context pool information */ +/* op(I) - pointer to iplookup struct with call details */ +/* Locks: WRITE(ipf_poolrw) */ /* */ /* Creates a new group according to the paramters passed in via the */ /* iplookupop structure. Does not check to see if the group already exists */ @@ -522,8 +945,11 @@ int info; /* as this likely means we've tried to free a pool that is in use (flush) */ /* and now want to repopulate it with "new" data. */ /* ------------------------------------------------------------------------ */ -int ip_pool_create(op) -iplookupop_t *op; +static int +ipf_pool_create(softc, softp, op) + ipf_main_softc_t *softc; + ipf_pool_softc_t *softp; + iplookupop_t *op; { char name[FR_GROUPLEN]; int poolnum, unit; @@ -532,23 +958,27 @@ iplookupop_t *op; unit = op->iplo_unit; if ((op->iplo_arg & LOOKUP_ANON) == 0) { - h = ip_pool_exists(unit, op->iplo_name); + h = ipf_pool_exists(softp, unit, op->iplo_name); if (h != NULL) { - if ((h->ipo_flags & IPOOL_DELETE) == 0) + if ((h->ipo_flags & IPOOL_DELETE) == 0) { + IPFERROR(70006); return EEXIST; + } h->ipo_flags &= ~IPOOL_DELETE; return 0; } } KMALLOC(h, ip_pool_t *); - if (h == NULL) + if (h == NULL) { + IPFERROR(70007); return ENOMEM; + } bzero(h, sizeof(*h)); - if (rn_inithead((void **)&h->ipo_head, - offsetof(addrfamily_t, adf_addr) << 3) == 0) { + if (ipf_rx_inithead(softp->ipf_radix, &h->ipo_head) != 0) { KFREE(h); + IPFERROR(70008); return ENOMEM; } @@ -564,7 +994,7 @@ iplookupop_t *op; (void)sprintf(name, "%x", poolnum); #endif - for (p = ip_pool_list[unit]; p != NULL; ) { + for (p = softp->ipf_pool_list[unit + 1]; p != NULL; ) { if (strncmp(name, p->ipo_name, sizeof(p->ipo_name)) == 0) { poolnum++; @@ -573,7 +1003,7 @@ iplookupop_t *op; #else (void)sprintf(name, "%x", poolnum); #endif - p = ip_pool_list[unit]; + p = softp->ipf_pool_list[unit + 1]; } else p = p->ipo_next; } @@ -584,121 +1014,144 @@ iplookupop_t *op; (void)strncpy(h->ipo_name, op->iplo_name, sizeof(h->ipo_name)); } + h->ipo_radix = softp->ipf_radix; h->ipo_ref = 1; h->ipo_list = NULL; + h->ipo_tail = &h->ipo_list; h->ipo_unit = unit; - h->ipo_next = ip_pool_list[unit]; - if (ip_pool_list[unit] != NULL) - ip_pool_list[unit]->ipo_pnext = &h->ipo_next; - h->ipo_pnext = &ip_pool_list[unit]; - ip_pool_list[unit] = h; + h->ipo_next = softp->ipf_pool_list[unit + 1]; + if (softp->ipf_pool_list[unit + 1] != NULL) + softp->ipf_pool_list[unit + 1]->ipo_pnext = &h->ipo_next; + h->ipo_pnext = &softp->ipf_pool_list[unit + 1]; + softp->ipf_pool_list[unit + 1] = h; - ipoolstat.ipls_pools++; + softp->ipf_pool_stats.ipls_pools++; return 0; } /* ------------------------------------------------------------------------ */ -/* Function: ip_pool_remove */ -/* Returns: int - 0 = success, else error */ -/* Parameters: ipo(I) - pointer to the pool to remove the node from. */ -/* ipe(I) - address being deleted as a node */ -/* Locks: WRITE(ip_poolrw) */ +/* Function: ipf_pool_remove_node */ +/* Returns: int - 0 = success, else error */ +/* Parameters: softc(I) - pointer to soft context main structure */ +/* ipo(I) - pointer to the pool to remove the node from. */ +/* ipe(I) - address being deleted as a node */ +/* Locks: WRITE(ipf_poolrw) */ /* */ /* Remove a node from the pool given by ipo. */ /* ------------------------------------------------------------------------ */ -int ip_pool_remove(ipo, ipe) -ip_pool_t *ipo; -ip_pool_node_t *ipe; +static int +ipf_pool_remove_node(softc, softp, ipo, ipe) + ipf_main_softc_t *softc; + ipf_pool_softc_t *softp; + ip_pool_t *ipo; + ip_pool_node_t *ipe; { + void *ptr; + + if (ipo->ipo_tail == &ipe->ipn_next) + ipo->ipo_tail = ipe->ipn_pnext; if (ipe->ipn_pnext != NULL) *ipe->ipn_pnext = ipe->ipn_next; if (ipe->ipn_next != NULL) ipe->ipn_next->ipn_pnext = ipe->ipn_pnext; - RADIX_NODE_HEAD_LOCK(ipo->ipo_head); - ipo->ipo_head->rnh_deladdr(&ipe->ipn_addr, &ipe->ipn_mask, - ipo->ipo_head); - RADIX_NODE_HEAD_UNLOCK(ipo->ipo_head); + if (ipe->ipn_pdnext != NULL) + *ipe->ipn_pdnext = ipe->ipn_dnext; + if (ipe->ipn_dnext != NULL) + ipe->ipn_dnext->ipn_pdnext = ipe->ipn_pdnext; - ip_pool_node_deref(ipe); + ptr = ipo->ipo_head->deladdr(ipo->ipo_head, &ipe->ipn_addr, + &ipe->ipn_mask); - return 0; + if (ptr != NULL) { + ipf_pool_node_deref(softp, ipe); + return 0; + } + IPFERROR(70027); + return ESRCH; } /* ------------------------------------------------------------------------ */ -/* Function: ip_pool_destroy */ +/* Function: ipf_pool_destroy */ /* Returns: int - 0 = success, else error */ -/* Parameters: op(I) - information about the pool to remove */ -/* Locks: WRITE(ip_poolrw) or WRITE(ipf_global) */ +/* Parameters: softc(I) - pointer to soft context main structure */ +/* softp(I) - pointer to soft context pool information */ +/* unit(I) - ipfilter device to which we are working on */ +/* name(I) - name of the pool */ +/* Locks: WRITE(ipf_poolrw) or WRITE(ipf_global) */ /* */ /* Search for a pool using paramters passed in and if it's not otherwise */ /* busy, free it. If it is busy, clear all of its nodes, mark it for being */ /* deleted and return an error saying it is busy. */ /* */ -/* NOTE: Because this function is called out of ipfdetach() where ip_poolrw */ +/* NOTE: Because this function is called out of ipfdetach() where ipf_poolrw*/ /* may not be initialised, we can't use an ASSERT to enforce the locking */ -/* assertion that one of the two (ip_poolrw,ipf_global) is held. */ +/* assertion that one of the two (ipf_poolrw,ipf_global) is held. */ /* ------------------------------------------------------------------------ */ -int ip_pool_destroy(unit, name) -int unit; -char *name; +static int +ipf_pool_destroy(softc, softp, unit, name) + ipf_main_softc_t *softc; + ipf_pool_softc_t *softp; + int unit; + char *name; { ip_pool_t *ipo; - ipo = ip_pool_exists(unit, name); - if (ipo == NULL) + ipo = ipf_pool_exists(softp, unit, name); + if (ipo == NULL) { + IPFERROR(70009); return ESRCH; + } if (ipo->ipo_ref != 1) { - ip_pool_clearnodes(ipo); + ipf_pool_clearnodes(softc, softp, ipo); ipo->ipo_flags |= IPOOL_DELETE; return 0; } - ip_pool_free(ipo); + ipf_pool_free(softc, softp, ipo); return 0; } /* ------------------------------------------------------------------------ */ -/* Function: ip_pool_flush */ +/* Function: ipf_pool_flush */ /* Returns: int - number of pools deleted */ -/* Parameters: fp(I) - which pool(s) to flush */ -/* Locks: WRITE(ip_poolrw) or WRITE(ipf_global) */ +/* Parameters: softc(I) - pointer to soft context main structure */ +/* arg(I) - pointer to local context to use */ +/* fp(I) - which pool(s) to flush */ +/* Locks: WRITE(ipf_poolrw) or WRITE(ipf_global) */ /* */ /* Free all pools associated with the device that matches the unit number */ /* passed in with operation. */ /* */ -/* NOTE: Because this function is called out of ipfdetach() where ip_poolrw */ +/* NOTE: Because this function is called out of ipfdetach() where ipf_poolrw*/ /* may not be initialised, we can't use an ASSERT to enforce the locking */ -/* assertion that one of the two (ip_poolrw,ipf_global) is held. */ +/* assertion that one of the two (ipf_poolrw,ipf_global) is held. */ /* ------------------------------------------------------------------------ */ -int ip_pool_flush(fp) -iplookupflush_t *fp; +static size_t +ipf_pool_flush(softc, arg, fp) + ipf_main_softc_t *softc; + void *arg; + iplookupflush_t *fp; { + ipf_pool_softc_t *softp = arg; int i, num = 0, unit, err; ip_pool_t *p, *q; - iplookupop_t op; unit = fp->iplf_unit; - - for (i = 0; i <= IPL_LOGMAX; i++) { + for (i = -1; i <= IPL_LOGMAX; i++) { if (unit != IPLT_ALL && i != unit) continue; - for (q = ip_pool_list[i]; (p = q) != NULL; ) { - op.iplo_unit = i; - (void)strncpy(op.iplo_name, p->ipo_name, - sizeof(op.iplo_name)); + for (q = softp->ipf_pool_list[i + 1]; (p = q) != NULL; ) { q = p->ipo_next; - err = ip_pool_destroy(op.iplo_unit, op.iplo_name); + err = ipf_pool_destroy(softc, softp, i, p->ipo_name); if (err == 0) num++; - else - break; } } return num; @@ -706,125 +1159,140 @@ iplookupflush_t *fp; /* ------------------------------------------------------------------------ */ -/* Function: ip_pool_free */ +/* Function: ipf_pool_free */ /* Returns: void */ -/* Parameters: ipo(I) - pointer to pool structure */ -/* Locks: WRITE(ip_poolrw) or WRITE(ipf_global) */ +/* Parameters: softc(I) - pointer to soft context main structure */ +/* softp(I) - pointer to soft context pool information */ +/* ipo(I) - pointer to pool structure */ +/* Locks: WRITE(ipf_poolrw) or WRITE(ipf_global) */ /* */ /* Deletes the pool strucutre passed in from the list of pools and deletes */ /* all of the address information stored in it, including any tree data */ /* structures also allocated. */ /* */ -/* NOTE: Because this function is called out of ipfdetach() where ip_poolrw */ +/* NOTE: Because this function is called out of ipfdetach() where ipf_poolrw*/ /* may not be initialised, we can't use an ASSERT to enforce the locking */ -/* assertion that one of the two (ip_poolrw,ipf_global) is held. */ +/* assertion that one of the two (ipf_poolrw,ipf_global) is held. */ /* ------------------------------------------------------------------------ */ -void ip_pool_free(ipo) -ip_pool_t *ipo; +static void +ipf_pool_free(softc, softp, ipo) + ipf_main_softc_t *softc; + ipf_pool_softc_t *softp; + ip_pool_t *ipo; { - ip_pool_clearnodes(ipo); + ipf_pool_clearnodes(softc, softp, ipo); if (ipo->ipo_next != NULL) ipo->ipo_next->ipo_pnext = ipo->ipo_pnext; *ipo->ipo_pnext = ipo->ipo_next; - rn_freehead(ipo->ipo_head); + ipf_rx_freehead(ipo->ipo_head); KFREE(ipo); - ipoolstat.ipls_pools--; + softp->ipf_pool_stats.ipls_pools--; } /* ------------------------------------------------------------------------ */ -/* Function: ip_pool_clearnodes */ +/* Function: ipf_pool_clearnodes */ /* Returns: void */ -/* Parameters: ipo(I) - pointer to pool structure */ -/* Locks: WRITE(ip_poolrw) or WRITE(ipf_global) */ +/* Parameters: softc(I) - pointer to soft context main structure */ +/* softp(I) - pointer to soft context pool information */ +/* ipo(I) - pointer to pool structure */ +/* Locks: WRITE(ipf_poolrw) or WRITE(ipf_global) */ /* */ /* Deletes all nodes stored in a pool structure. */ /* ------------------------------------------------------------------------ */ -static void ip_pool_clearnodes(ipo) -ip_pool_t *ipo; +static void +ipf_pool_clearnodes(softc, softp, ipo) + ipf_main_softc_t *softc; + ipf_pool_softc_t *softp; + ip_pool_t *ipo; { - ip_pool_node_t *n; - - RADIX_NODE_HEAD_LOCK(ipo->ipo_head); - while ((n = ipo->ipo_list) != NULL) { - ipo->ipo_head->rnh_deladdr(&n->ipn_addr, &n->ipn_mask, - ipo->ipo_head); - - *n->ipn_pnext = n->ipn_next; - if (n->ipn_next) - n->ipn_next->ipn_pnext = n->ipn_pnext; - - KFREE(n); + ip_pool_node_t *n, **next; - ipoolstat.ipls_nodes--; - } - RADIX_NODE_HEAD_UNLOCK(ipo->ipo_head); + for (next = &ipo->ipo_list; (n = *next) != NULL; ) + ipf_pool_remove_node(softc, softp, ipo, n); ipo->ipo_list = NULL; } /* ------------------------------------------------------------------------ */ -/* Function: ip_pool_deref */ +/* Function: ipf_pool_deref */ /* Returns: void */ -/* Parameters: ipo(I) - pointer to pool structure */ -/* Locks: WRITE(ip_poolrw) */ +/* Parameters: softc(I) - pointer to soft context main structure */ +/* arg(I) - pointer to local context to use */ +/* pool(I) - pointer to pool structure */ +/* Locks: WRITE(ipf_poolrw) */ /* */ /* Drop the number of known references to this pool structure by one and if */ /* we arrive at zero known references, free it. */ /* ------------------------------------------------------------------------ */ -void ip_pool_deref(ipo) -ip_pool_t *ipo; +static int +ipf_pool_deref(softc, arg, pool) + ipf_main_softc_t *softc; + void *arg, *pool; { + ip_pool_t *ipo = pool; ipo->ipo_ref--; if (ipo->ipo_ref == 0) - ip_pool_free(ipo); + ipf_pool_free(softc, arg, ipo); else if ((ipo->ipo_ref == 1) && (ipo->ipo_flags & IPOOL_DELETE)) - ip_pool_destroy(ipo->ipo_unit, ipo->ipo_name); + ipf_pool_destroy(softc, arg, ipo->ipo_unit, ipo->ipo_name); + + return 0; } /* ------------------------------------------------------------------------ */ -/* Function: ip_pool_node_deref */ +/* Function: ipf_pool_node_deref */ /* Returns: void */ -/* Parameters: ipn(I) - pointer to pool structure */ -/* Locks: WRITE(ip_poolrw) */ +/* Parameters: softp(I) - pointer to soft context pool information */ +/* ipn(I) - pointer to pool structure */ +/* Locks: WRITE(ipf_poolrw) */ /* */ /* Drop a reference to the pool node passed in and if we're the last, free */ /* it all up and adjust the stats accordingly. */ /* ------------------------------------------------------------------------ */ -void ip_pool_node_deref(ipn) -ip_pool_node_t *ipn; +static void +ipf_pool_node_deref(softp, ipn) + ipf_pool_softc_t *softp; + ip_pool_node_t *ipn; { ipn->ipn_ref--; if (ipn->ipn_ref == 0) { KFREE(ipn); - ipoolstat.ipls_nodes--; + softp->ipf_pool_stats.ipls_nodes--; } } /* ------------------------------------------------------------------------ */ -/* Function: ip_pool_getnext */ +/* Function: ipf_pool_iter_next */ /* Returns: void */ -/* Parameters: token(I) - pointer to pool structure */ -/* Parameters: ilp(IO) - pointer to pool iterating structure */ +/* Parameters: softc(I) - pointer to soft context main structure */ +/* arg(I) - pointer to local context to use */ +/* token(I) - pointer to pool structure */ +/* ilp(IO) - pointer to pool iterating structure */ /* */ /* ------------------------------------------------------------------------ */ -int ip_pool_getnext(token, ilp) -ipftoken_t *token; -ipflookupiter_t *ilp; +static int +ipf_pool_iter_next(softc, arg, token, ilp) + ipf_main_softc_t *softc; + void *arg; + ipftoken_t *token; + ipflookupiter_t *ilp; { + ipf_pool_softc_t *softp = arg; ip_pool_node_t *node, zn, *nextnode; ip_pool_t *ipo, zp, *nextipo; + void *pnext; int err; err = 0; @@ -833,35 +1301,38 @@ ipflookupiter_t *ilp; ipo = NULL; nextipo = NULL; - READ_ENTER(&ip_poolrw); + READ_ENTER(&softc->ipf_poolrw); switch (ilp->ili_otype) { case IPFLOOKUPITER_LIST : ipo = token->ipt_data; if (ipo == NULL) { - nextipo = ip_pool_list[(int)ilp->ili_unit]; + nextipo = softp->ipf_pool_list[(int)ilp->ili_unit + 1]; } else { nextipo = ipo->ipo_next; } if (nextipo != NULL) { - ATOMIC_INC(nextipo->ipo_ref); + ATOMIC_INC32(nextipo->ipo_ref); token->ipt_data = nextipo; } else { bzero((char *)&zp, sizeof(zp)); nextipo = &zp; token->ipt_data = NULL; } + pnext = nextipo->ipo_next; break; case IPFLOOKUPITER_NODE : node = token->ipt_data; if (node == NULL) { - ipo = ip_pool_exists(ilp->ili_unit, ilp->ili_name); - if (ipo == NULL) + ipo = ipf_pool_exists(arg, ilp->ili_unit, + ilp->ili_name); + if (ipo == NULL) { + IPFERROR(70010); err = ESRCH; - else { + } else { nextnode = ipo->ipo_list; ipo = NULL; } @@ -870,123 +1341,149 @@ ipflookupiter_t *ilp; } if (nextnode != NULL) { - ATOMIC_INC(nextnode->ipn_ref); + ATOMIC_INC32(nextnode->ipn_ref); token->ipt_data = nextnode; } else { bzero((char *)&zn, sizeof(zn)); nextnode = &zn; token->ipt_data = NULL; } + pnext = nextnode->ipn_next; break; + default : + IPFERROR(70011); + pnext = NULL; err = EINVAL; break; } - RWLOCK_EXIT(&ip_poolrw); - + RWLOCK_EXIT(&softc->ipf_poolrw); if (err != 0) return err; switch (ilp->ili_otype) { case IPFLOOKUPITER_LIST : - if (ipo != NULL) { - WRITE_ENTER(&ip_poolrw); - ip_pool_deref(ipo); - RWLOCK_EXIT(&ip_poolrw); - } err = COPYOUT(nextipo, ilp->ili_data, sizeof(*nextipo)); - if (err != 0) + if (err != 0) { + IPFERROR(70012); err = EFAULT; + } + if (ipo != NULL) { + WRITE_ENTER(&softc->ipf_poolrw); + ipf_pool_deref(softc, softp, ipo); + RWLOCK_EXIT(&softc->ipf_poolrw); + } break; case IPFLOOKUPITER_NODE : - if (node != NULL) { - WRITE_ENTER(&ip_poolrw); - ip_pool_node_deref(node); - RWLOCK_EXIT(&ip_poolrw); - } err = COPYOUT(nextnode, ilp->ili_data, sizeof(*nextnode)); - if (err != 0) + if (err != 0) { + IPFERROR(70013); err = EFAULT; + } + if (node != NULL) { + WRITE_ENTER(&softc->ipf_poolrw); + ipf_pool_node_deref(softp, node); + RWLOCK_EXIT(&softc->ipf_poolrw); + } break; } + if (pnext == NULL) + ipf_token_mark_complete(token); return err; } /* ------------------------------------------------------------------------ */ -/* Function: ip_pool_iterderef */ +/* Function: ipf_pool_iterderef */ /* Returns: void */ -/* Parameters: ipn(I) - pointer to pool structure */ -/* Locks: WRITE(ip_poolrw) */ +/* Parameters: softc(I) - pointer to soft context main structure */ +/* arg(I) - pointer to local context to use */ +/* unit(I) - ipfilter device to which we are working on */ +/* Locks: WRITE(ipf_poolrw) */ /* */ /* ------------------------------------------------------------------------ */ -void ip_pool_iterderef(otype, unit, data) -u_int otype; -int unit; -void *data; +static int +ipf_pool_iter_deref(softc, arg, otype, unit, data) + ipf_main_softc_t *softc; + void *arg; + int otype; + int unit; + void *data; { + ipf_pool_softc_t *softp = arg; if (data == NULL) - return; + return EINVAL; if (unit < 0 || unit > IPL_LOGMAX) - return; + return EINVAL; switch (otype) { case IPFLOOKUPITER_LIST : - WRITE_ENTER(&ip_poolrw); - ip_pool_deref((ip_pool_t *)data); - RWLOCK_EXIT(&ip_poolrw); + ipf_pool_deref(softc, softp, (ip_pool_t *)data); break; case IPFLOOKUPITER_NODE : - WRITE_ENTER(&ip_poolrw); - ip_pool_node_deref((ip_pool_node_t *)data); - RWLOCK_EXIT(&ip_poolrw); + ipf_pool_node_deref(softp, (ip_pool_node_t *)data); break; default : break; } + + return 0; } -# if defined(_KERNEL) && ((BSD >= 198911) && !defined(__osf__) && \ - !defined(__hpux) && !defined(__sgi)) -static int -rn_freenode(struct radix_node *n, void *p) +/* ------------------------------------------------------------------------ */ +/* Function: ipf_pool_expire */ +/* Returns: Nil */ +/* Parameters: softc(I) - pointer to soft context main structure */ +/* arg(I) - pointer to local context to use */ +/* */ +/* At present this function exists just to support temporary addition of */ +/* nodes to the address pool. */ +/* ------------------------------------------------------------------------ */ +static void +ipf_pool_expire(softc, arg) + ipf_main_softc_t *softc; + void *arg; { - struct radix_node_head *rnh = p; - struct radix_node *d; + ipf_pool_softc_t *softp = arg; + ip_pool_node_t *n; - d = rnh->rnh_deladdr(n->rn_key, NULL, rnh); - if (d != NULL) { - FreeS(d, max_keylen + 2 * sizeof (*d)); + while ((n = softp->ipf_node_explist) != NULL) { + /* + * Because the list is kept sorted on insertion, the fist + * one that dies in the future means no more work to do. + */ + if (n->ipn_die > softc->ipf_ticks) + break; + ipf_pool_remove_node(softc, softp, n->ipn_owner, n); } - return 0; } -void -rn_freehead(rnh) - struct radix_node_head *rnh; -{ - RADIX_NODE_HEAD_LOCK(rnh); - (*rnh->rnh_walktree)(rnh, rn_freenode, rnh); - rnh->rnh_addaddr = NULL; - rnh->rnh_deladdr = NULL; - rnh->rnh_matchaddr = NULL; - rnh->rnh_lookup = NULL; - rnh->rnh_walktree = NULL; - RADIX_NODE_HEAD_UNLOCK(rnh); +#ifndef _KERNEL +void +ipf_pool_dump(softc, arg) + ipf_main_softc_t *softc; + void *arg; +{ + ipf_pool_softc_t *softp = arg; + ip_pool_t *ipl; + int i; - Free(rnh); + printf("List of configured pools\n"); + for (i = 0; i <= LOOKUP_POOL_MAX; i++) + for (ipl = softp->ipf_pool_list[i]; ipl != NULL; + ipl = ipl->ipo_next) + printpool(ipl, bcopywrap, NULL, opts, NULL); } -# endif -#endif /* IPFILTER_LOOKUP */ +#endif |