Home | History | Annotate | Line # | Download | only in netinet
ip_pool.c revision 1.2.4.3
      1 /*	$NetBSD: ip_pool.c,v 1.2.4.3 2012/10/30 17:22:20 yamt Exp $	*/
      2 
      3 /*
      4  * Copyright (C) 2012 by Darren Reed.
      5  *
      6  * See the IPFILTER.LICENCE file for details on licencing.
      7  */
      8 #if defined(KERNEL) || defined(_KERNEL)
      9 # undef KERNEL
     10 # undef _KERNEL
     11 # define        KERNEL	1
     12 # define        _KERNEL	1
     13 #endif
     14 #if defined(__osf__)
     15 # define _PROTO_NET_H_
     16 #endif
     17 #include <sys/errno.h>
     18 #include <sys/types.h>
     19 #include <sys/param.h>
     20 #if defined(__NetBSD__)
     21 # if (NetBSD >= 199905) && !defined(IPFILTER_LKM) && defined(_KERNEL)
     22 #  include "opt_ipfilter.h"
     23 # endif
     24 #endif
     25 #include <sys/file.h>
     26 #if !defined(_KERNEL) && !defined(__KERNEL__)
     27 # include <stdio.h>
     28 # include <stdlib.h>
     29 # include <string.h>
     30 # define _KERNEL
     31 # ifdef __OpenBSD__
     32 struct file;
     33 # endif
     34 # include <sys/uio.h>
     35 # undef _KERNEL
     36 #else
     37 # include <sys/systm.h>
     38 # if defined(NetBSD) && (__NetBSD_Version__ >= 104000000)
     39 #  include <sys/proc.h>
     40 # endif
     41 #endif
     42 #include <sys/time.h>
     43 #if defined(_KERNEL) && !defined(SOLARIS2)
     44 # include <sys/mbuf.h>
     45 #endif
     46 #if defined(__SVR4) || defined(__svr4__)
     47 # include <sys/byteorder.h>
     48 # ifdef _KERNEL
     49 #  include <sys/dditypes.h>
     50 # endif
     51 # include <sys/stream.h>
     52 # include <sys/kmem.h>
     53 #endif
     54 #if defined(__FreeBSD_version) && (__FreeBSD_version >= 300000)
     55 # include <sys/malloc.h>
     56 #endif
     57 
     58 #include <sys/socket.h>
     59 #include <net/if.h>
     60 #include <netinet/in.h>
     61 #if !defined(_KERNEL)
     62 # include "ipf.h"
     63 #endif
     64 
     65 #include "netinet/ip_compat.h"
     66 #include "netinet/ip_fil.h"
     67 #include "netinet/ip_pool.h"
     68 #include "netinet/radix_ipf.h"
     69 
     70 /* END OF INCLUDES */
     71 
     72 #if !defined(lint)
     73 #if defined(__NetBSD__)
     74 #include <sys/cdefs.h>
     75 __KERNEL_RCSID(0, "$NetBSD: ip_pool.c,v 1.2.4.3 2012/10/30 17:22:20 yamt Exp $");
     76 #else
     77 static const char sccsid[] = "@(#)ip_fil.c	2.41 6/5/96 (C) 1993-2000 Darren Reed";
     78 static const char rcsid[] = "@(#)Id: ip_pool.c,v 1.1.1.2 2012/07/22 13:45:31 darrenr Exp";
     79 #endif
     80 #endif
     81 
     82 typedef struct ipf_pool_softc_s {
     83 	void		*ipf_radix;
     84 	ip_pool_t	*ipf_pool_list[LOOKUP_POOL_SZ];
     85 	ipf_pool_stat_t	ipf_pool_stats;
     86 	ip_pool_node_t	*ipf_node_explist;
     87 } ipf_pool_softc_t;
     88 
     89 
     90 static void ipf_pool_clearnodes(ipf_main_softc_t *, ipf_pool_softc_t *,
     91 				     ip_pool_t *);
     92 static int ipf_pool_create(ipf_main_softc_t *, ipf_pool_softc_t *, iplookupop_t *);
     93 static int ipf_pool_deref(ipf_main_softc_t *, void *, void *);
     94 static int ipf_pool_destroy(ipf_main_softc_t *, ipf_pool_softc_t *, int, char *);
     95 static void *ipf_pool_exists(ipf_pool_softc_t *, int, char *);
     96 static void *ipf_pool_find(void *, int, char *);
     97 static ip_pool_node_t *ipf_pool_findeq(ipf_pool_softc_t *, ip_pool_t *,
     98 					    addrfamily_t *, addrfamily_t *);
     99 static void ipf_pool_free(ipf_main_softc_t *, ipf_pool_softc_t *, ip_pool_t *);
    100 static int ipf_pool_insert_node(ipf_main_softc_t *, ipf_pool_softc_t *,
    101 				     ip_pool_t *, struct ip_pool_node *);
    102 static int ipf_pool_iter_deref(ipf_main_softc_t *, void *, int, int, void *);
    103 static int ipf_pool_iter_next(ipf_main_softc_t *,  void *, ipftoken_t *,
    104 				   ipflookupiter_t *);
    105 static size_t ipf_pool_flush(ipf_main_softc_t *, void *, iplookupflush_t *);
    106 static int ipf_pool_node_add(ipf_main_softc_t *, void *, iplookupop_t *,
    107 				  int);
    108 static int ipf_pool_node_del(ipf_main_softc_t *, void *, iplookupop_t *,
    109 				  int);
    110 static void ipf_pool_node_deref(ipf_pool_softc_t *, ip_pool_node_t *);
    111 static int ipf_pool_remove_node(ipf_main_softc_t *, ipf_pool_softc_t *,
    112 				ip_pool_t *, ip_pool_node_t *);
    113 static int ipf_pool_search(ipf_main_softc_t *, void *, int,
    114 				void *, u_int);
    115 static void *ipf_pool_soft_create(ipf_main_softc_t *);
    116 static void ipf_pool_soft_destroy(ipf_main_softc_t *, void *);
    117 static void ipf_pool_soft_fini(ipf_main_softc_t *, void *);
    118 static int ipf_pool_soft_init(ipf_main_softc_t *, void *);
    119 static int ipf_pool_stats_get(ipf_main_softc_t *, void *, iplookupop_t *);
    120 static int ipf_pool_table_add(ipf_main_softc_t *, void *, iplookupop_t *);
    121 static int ipf_pool_table_del(ipf_main_softc_t *, void *, iplookupop_t *);
    122 static void *ipf_pool_select_add_ref(void *, int, char *);
    123 static void ipf_pool_expire(ipf_main_softc_t *, void *);
    124 
    125 ipf_lookup_t ipf_pool_backend = {
    126 	IPLT_POOL,
    127 	ipf_pool_soft_create,
    128 	ipf_pool_soft_destroy,
    129 	ipf_pool_soft_init,
    130 	ipf_pool_soft_fini,
    131 	ipf_pool_search,
    132 	ipf_pool_flush,
    133 	ipf_pool_iter_deref,
    134 	ipf_pool_iter_next,
    135 	ipf_pool_node_add,
    136 	ipf_pool_node_del,
    137 	ipf_pool_stats_get,
    138 	ipf_pool_table_add,
    139 	ipf_pool_table_del,
    140 	ipf_pool_deref,
    141 	ipf_pool_find,
    142 	ipf_pool_select_add_ref,
    143 	NULL,
    144 	ipf_pool_expire,
    145 	NULL
    146 };
    147 
    148 
    149 #ifdef TEST_POOL
    150 void treeprint(ip_pool_t *);
    151 
    152 int
    153 main(argc, argv)
    154 	int argc;
    155 	char *argv[];
    156 {
    157 	ip_pool_node_t node;
    158 	addrfamily_t a, b;
    159 	iplookupop_t op;
    160 	ip_pool_t *ipo;
    161 	i6addr_t ip;
    162 
    163 	RWLOCK_INIT(softc->ipf_poolrw, "poolrw");
    164 	ipf_pool_init();
    165 
    166 	bzero((char *)&ip, sizeof(ip));
    167 	bzero((char *)&op, sizeof(op));
    168 	bzero((char *)&node, sizeof(node));
    169 	strlcpy(op.iplo_name, "0", sizeof(op.iplo_name));
    170 
    171 	if (ipf_pool_create(&op) == 0)
    172 		ipo = ipf_pool_exists(0, "0");
    173 
    174 	node.ipn_addr.adf_family = AF_INET;
    175 
    176 	node.ipn_addr.adf_addr.in4.s_addr = 0x0a010203;
    177 	node.ipn_mask.adf_addr.in4.s_addr = 0xffffffff;
    178 	node.ipn_info = 1;
    179 	ipf_pool_insert_node(ipo, &node);
    180 
    181 	node.ipn_addr.adf_addr.in4.s_addr = 0x0a000000;
    182 	node.ipn_mask.adf_addr.in4.s_addr = 0xff000000;
    183 	node.ipn_info = 0;
    184 	ipf_pool_insert_node(ipo, &node);
    185 
    186 	node.ipn_addr.adf_addr.in4.s_addr = 0x0a010100;
    187 	node.ipn_mask.adf_addr.in4.s_addr = 0xffffff00;
    188 	node.ipn_info = 1;
    189 	ipf_pool_insert_node(ipo, &node);
    190 
    191 	node.ipn_addr.adf_addr.in4.s_addr = 0x0a010200;
    192 	node.ipn_mask.adf_addr.in4.s_addr = 0xffffff00;
    193 	node.ipn_info = 0;
    194 	ipf_pool_insert_node(ipo, &node);
    195 
    196 	node.ipn_addr.adf_addr.in4.s_addr = 0x0a010000;
    197 	node.ipn_mask.adf_addr.in4.s_addr = 0xffff0000;
    198 	node.ipn_info = 1;
    199 	ipf_pool_insert_node(ipo, &node);
    200 
    201 	node.ipn_addr.adf_addr.in4.s_addr = 0x0a01020f;
    202 	node.ipn_mask.adf_addr.in4.s_addr = 0xffffffff;
    203 	node.ipn_info = 1;
    204 	ipf_pool_insert_node(ipo, &node);
    205 #ifdef	DEBUG_POOL
    206 	treeprint(ipo);
    207 #endif
    208 	ip.in4.s_addr = 0x0a00aabb;
    209 	printf("search(%#x) = %d (0)\n", ip.in4.s_addr,
    210 		ipf_pool_search(ipo, 4, &ip, 1));
    211 
    212 	ip.in4.s_addr = 0x0a000001;
    213 	printf("search(%#x) = %d (0)\n", ip.in4.s_addr,
    214 		ipf_pool_search(ipo, 4, &ip, 1));
    215 
    216 	ip.in4.s_addr = 0x0a000101;
    217 	printf("search(%#x) = %d (0)\n", ip.in4.s_addr,
    218 		ipf_pool_search(ipo, 4, &ip, 1));
    219 
    220 	ip.in4.s_addr = 0x0a010001;
    221 	printf("search(%#x) = %d (1)\n", ip.in4.s_addr,
    222 		ipf_pool_search(ipo, 4, &ip, 1));
    223 
    224 	ip.in4.s_addr = 0x0a010101;
    225 	printf("search(%#x) = %d (1)\n", ip.in4.s_addr,
    226 		ipf_pool_search(ipo, 4, &ip, 1));
    227 
    228 	ip.in4.s_addr = 0x0a010201;
    229 	printf("search(%#x) = %d (0)\n", ip.in4.s_addr,
    230 		ipf_pool_search(ipo, 4, &ip, 1));
    231 
    232 	ip.in4.s_addr = 0x0a010203;
    233 	printf("search(%#x) = %d (1)\n", ip.in4.s_addr,
    234 		ipf_pool_search(ipo, 4, &ip, 1));
    235 
    236 	ip.in4.s_addr = 0x0a01020f;
    237 	printf("search(%#x) = %d (1)\n", ip.in4.s_addr,
    238 		ipf_pool_search(ipo, 4, &ip, 1));
    239 
    240 	ip.in4.s_addr = 0x0b00aabb;
    241 	printf("search(%#x) = %d (-1)\n", ip.in4.s_addr,
    242 		ipf_pool_search(ipo, 4, &ip, 1));
    243 
    244 #ifdef	DEBUG_POOL
    245 	treeprint(ipo);
    246 #endif
    247 
    248 	ipf_pool_fini();
    249 
    250 	return 0;
    251 }
    252 
    253 
    254 void
    255 treeprint(ipo)
    256 	ip_pool_t *ipo;
    257 {
    258 	ip_pool_node_t *c;
    259 
    260 	for (c = ipo->ipo_list; c != NULL; c = c->ipn_next)
    261 		printf("Node %p(%s) (%#x/%#x) = %d hits %lu\n",
    262 			c, c->ipn_name, c->ipn_addr.adf_addr.in4.s_addr,
    263 			c->ipn_mask.adf_addr.in4.s_addr,
    264 			c->ipn_info, c->ipn_hits);
    265 }
    266 #endif /* TEST_POOL */
    267 
    268 
    269 /* ------------------------------------------------------------------------ */
    270 /* Function:    ipf_pool_soft_create                                        */
    271 /* Returns:     void *   - NULL = failure, else pointer to local context    */
    272 /* Parameters:  softc(I) - pointer to soft context main structure           */
    273 /*                                                                          */
    274 /* Initialise the routing table data structures where required.             */
    275 /* ------------------------------------------------------------------------ */
    276 static void *
    277 ipf_pool_soft_create(ipf_main_softc_t *softc)
    278 {
    279 	ipf_pool_softc_t *softp;
    280 
    281 	KMALLOC(softp, ipf_pool_softc_t *);
    282 	if (softp == NULL) {
    283 		IPFERROR(70032);
    284 		return NULL;
    285 	}
    286 
    287 	bzero((char *)softp, sizeof(*softp));
    288 
    289 	softp->ipf_radix = ipf_rx_create();
    290 	if (softp->ipf_radix == NULL) {
    291 		IPFERROR(70033);
    292 		KFREE(softp);
    293 		return NULL;
    294 	}
    295 
    296 	return softp;
    297 }
    298 
    299 
    300 /* ------------------------------------------------------------------------ */
    301 /* Function:    ipf_pool_soft_init                                          */
    302 /* Returns:     int     - 0 = success, else error                           */
    303 /* Parameters:  softc(I) - pointer to soft context main structure           */
    304 /*              arg(I)   - pointer to local context to use                  */
    305 /*                                                                          */
    306 /* Initialise the routing table data structures where required.             */
    307 /* ------------------------------------------------------------------------ */
    308 static int
    309 ipf_pool_soft_init(ipf_main_softc_t *softc, void *arg)
    310 {
    311 	ipf_pool_softc_t *softp = arg;
    312 
    313 	ipf_rx_init(softp->ipf_radix);
    314 
    315 	return 0;
    316 }
    317 
    318 
    319 /* ------------------------------------------------------------------------ */
    320 /* Function:    ipf_pool_soft_fini                                          */
    321 /* Returns:     Nil                                                         */
    322 /* Parameters:  softc(I) - pointer to soft context main structure           */
    323 /*              arg(I)   - pointer to local context to use                  */
    324 /* Locks:       WRITE(ipf_global)                                           */
    325 /*                                                                          */
    326 /* Clean up all the pool data structures allocated and call the cleanup     */
    327 /* function for the radix tree that supports the pools. ipf_pool_destroy is */
    328 /* used to delete the pools one by one to ensure they're properly freed up. */
    329 /* ------------------------------------------------------------------------ */
    330 static void
    331 ipf_pool_soft_fini(ipf_main_softc_t *softc, void *arg)
    332 {
    333 	ipf_pool_softc_t *softp = arg;
    334 	ip_pool_t *p, *q;
    335 	int i;
    336 
    337 	softc = arg;
    338 
    339 	for (i = -1; i <= IPL_LOGMAX; i++) {
    340 		for (q = softp->ipf_pool_list[i + 1]; (p = q) != NULL; ) {
    341 			q = p->ipo_next;
    342 			(void) ipf_pool_destroy(softc, arg, i, p->ipo_name);
    343 		}
    344 	}
    345 }
    346 
    347 
    348 /* ------------------------------------------------------------------------ */
    349 /* Function:    ipf_pool_soft_destroy                                       */
    350 /* Returns:     Nil                                                         */
    351 /* Parameters:  softc(I) - pointer to soft context main structure           */
    352 /*              arg(I)   - pointer to local context to use                  */
    353 /*                                                                          */
    354 /* Clean up the pool by free'ing the radix tree associated with it and free */
    355 /* up the pool context too.                                                 */
    356 /* ------------------------------------------------------------------------ */
    357 static void
    358 ipf_pool_soft_destroy(ipf_main_softc_t *softc, void *arg)
    359 {
    360 	ipf_pool_softc_t *softp = arg;
    361 
    362 	ipf_rx_destroy(softp->ipf_radix);
    363 
    364 	KFREE(softp);
    365 }
    366 
    367 
    368 /* ------------------------------------------------------------------------ */
    369 /* Function:   ipf_pool_node_add                                            */
    370 /* Returns:    int - 0 = success, else error                                */
    371 /* Parameters: softc(I) - pointer to soft context main structure            */
    372 /*             arg(I)   - pointer to local context to use                   */
    373 /*             op(I) - pointer to lookup operatin data                      */
    374 /*                                                                          */
    375 /* When adding a new node, a check is made to ensure that the address/mask  */
    376 /* pair supplied has been appropriately prepared by applying the mask to    */
    377 /* the address prior to calling for the pair to be added.                   */
    378 /* ------------------------------------------------------------------------ */
    379 static int
    380 ipf_pool_node_add(ipf_main_softc_t *softc, void *arg, iplookupop_t *op, int uid)
    381 {
    382 	ip_pool_node_t node, *m;
    383 	ip_pool_t *p;
    384 	int err;
    385 
    386 	if (op->iplo_size != sizeof(node)) {
    387 		IPFERROR(70014);
    388 		return EINVAL;
    389 	}
    390 
    391 	err = COPYIN(op->iplo_struct, &node, sizeof(node));
    392 	if (err != 0) {
    393 		IPFERROR(70015);
    394 		return EFAULT;
    395 	}
    396 
    397 	p = ipf_pool_find(arg, op->iplo_unit, op->iplo_name);
    398 	if (p == NULL) {
    399 		IPFERROR(70017);
    400 		return ESRCH;
    401 	}
    402 
    403 	if (node.ipn_addr.adf_family == AF_INET) {
    404 		if (node.ipn_addr.adf_len != offsetof(addrfamily_t, adf_addr) +
    405 					     sizeof(struct in_addr)) {
    406 			IPFERROR(70028);
    407 			return EINVAL;
    408 		}
    409 	}
    410 #ifdef USE_INET6
    411 	else if (node.ipn_addr.adf_family == AF_INET6) {
    412 		if (node.ipn_addr.adf_len != offsetof(addrfamily_t, adf_addr) +
    413 					     sizeof(struct in6_addr)) {
    414 			IPFERROR(70034);
    415 			return EINVAL;
    416 		}
    417 	}
    418 #endif
    419 	if (node.ipn_mask.adf_len != node.ipn_addr.adf_len) {
    420 		IPFERROR(70029);
    421 		return EINVAL;
    422 	}
    423 
    424 	/*
    425 	 * Check that the address/mask pair works.
    426 	 */
    427 	if (node.ipn_addr.adf_family == AF_INET) {
    428 		if ((node.ipn_addr.adf_addr.in4.s_addr &
    429 		     node.ipn_mask.adf_addr.in4.s_addr) !=
    430 		    node.ipn_addr.adf_addr.in4.s_addr) {
    431 			IPFERROR(70035);
    432 			return EINVAL;
    433 		}
    434 	}
    435 #ifdef USE_INET6
    436 	else if (node.ipn_addr.adf_family == AF_INET6) {
    437 		if (IP6_MASKNEQ(&node.ipn_addr.adf_addr.in6,
    438 				&node.ipn_mask.adf_addr.in6,
    439 				&node.ipn_addr.adf_addr.in6)) {
    440 			IPFERROR(70036);
    441 			return EINVAL;
    442 		}
    443 	}
    444 #endif
    445 
    446 	/*
    447 	 * add an entry to a pool - return an error if it already
    448 	 * exists remove an entry from a pool - if it exists
    449 	 * - in both cases, the pool *must* exist!
    450 	 */
    451 	m = ipf_pool_findeq(arg, p, &node.ipn_addr, &node.ipn_mask);
    452 	if (m != NULL) {
    453 		IPFERROR(70018);
    454 		return EEXIST;
    455 	}
    456 	err = ipf_pool_insert_node(softc, arg, p, &node);
    457 
    458 	return err;
    459 }
    460 
    461 
    462 /* ------------------------------------------------------------------------ */
    463 /* Function:   ipf_pool_node_del                                            */
    464 /* Returns:    int - 0 = success, else error                                */
    465 /* Parameters: softc(I) - pointer to soft context main structure            */
    466 /*             arg(I)   - pointer to local context to use                   */
    467 /*             op(I)    - pointer to lookup operatin data                   */
    468 /*                                                                          */
    469 /* ------------------------------------------------------------------------ */
    470 static int
    471 ipf_pool_node_del(ipf_main_softc_t *softc, void *arg, iplookupop_t *op, int uid)
    472 {
    473 	ip_pool_node_t node, *m;
    474 	ip_pool_t *p;
    475 	int err;
    476 
    477 
    478 	if (op->iplo_size != sizeof(node)) {
    479 		IPFERROR(70019);
    480 		return EINVAL;
    481 	}
    482 	node.ipn_uid = uid;
    483 
    484 	err = COPYIN(op->iplo_struct, &node, sizeof(node));
    485 	if (err != 0) {
    486 		IPFERROR(70020);
    487 		return EFAULT;
    488 	}
    489 
    490 	if (node.ipn_addr.adf_family == AF_INET) {
    491 		if (node.ipn_addr.adf_len != offsetof(addrfamily_t, adf_addr) +
    492 					     sizeof(struct in_addr)) {
    493 			IPFERROR(70030);
    494 			return EINVAL;
    495 		}
    496 	}
    497 #ifdef USE_INET6
    498 	else if (node.ipn_addr.adf_family == AF_INET6) {
    499 		if (node.ipn_addr.adf_len != offsetof(addrfamily_t, adf_addr) +
    500 					     sizeof(struct in6_addr)) {
    501 			IPFERROR(70037);
    502 			return EINVAL;
    503 		}
    504 	}
    505 #endif
    506 	if (node.ipn_mask.adf_len != node.ipn_addr.adf_len) {
    507 		IPFERROR(70031);
    508 		return EINVAL;
    509 	}
    510 
    511 	p = ipf_pool_find(arg, op->iplo_unit, op->iplo_name);
    512 	if (p == NULL) {
    513 		IPFERROR(70021);
    514 		return ESRCH;
    515 	}
    516 
    517 	m = ipf_pool_findeq(arg, p, &node.ipn_addr, &node.ipn_mask);
    518 	if (m == NULL) {
    519 		IPFERROR(70022);
    520 		return ENOENT;
    521 	}
    522 
    523 	if ((uid != 0) && (uid != m->ipn_uid)) {
    524 		IPFERROR(70024);
    525 		return EACCES;
    526 	}
    527 
    528 	err = ipf_pool_remove_node(softc, arg, p, m);
    529 
    530 	return err;
    531 }
    532 
    533 
    534 /* ------------------------------------------------------------------------ */
    535 /* Function:   ipf_pool_table_add                                           */
    536 /* Returns:    int - 0 = success, else error                                */
    537 /* Parameters: softc(I) - pointer to soft context main structure            */
    538 /*             arg(I)   - pointer to local context to use                   */
    539 /*             op(I)    - pointer to lookup operatin data                   */
    540 /*                                                                          */
    541 /* ------------------------------------------------------------------------ */
    542 static int
    543 ipf_pool_table_add(ipf_main_softc_t *softc, void *arg, iplookupop_t *op)
    544 {
    545 	int err;
    546 
    547 	if (((op->iplo_arg & LOOKUP_ANON) == 0) &&
    548 	    (ipf_pool_find(arg, op->iplo_unit, op->iplo_name) != NULL)) {
    549 		IPFERROR(70023);
    550 		err = EEXIST;
    551 	} else {
    552 		err = ipf_pool_create(softc, arg, op);
    553 	}
    554 
    555 	return err;
    556 }
    557 
    558 
    559 /* ------------------------------------------------------------------------ */
    560 /* Function:   ipf_pool_table_del                                           */
    561 /* Returns:    int - 0 = success, else error                                */
    562 /* Parameters: softc(I) - pointer to soft context main structure            */
    563 /*             arg(I)   - pointer to local context to use                   */
    564 /*             op(I)    - pointer to lookup operatin data                   */
    565 /*                                                                          */
    566 /* ------------------------------------------------------------------------ */
    567 static int
    568 ipf_pool_table_del(ipf_main_softc_t *softc, void *arg, iplookupop_t *op)
    569 {
    570 	return ipf_pool_destroy(softc, arg, op->iplo_unit, op->iplo_name);
    571 }
    572 
    573 
    574 /* ------------------------------------------------------------------------ */
    575 /* Function:    ipf_pool_statistics                                         */
    576 /* Returns:     int      - 0 = success, else error                          */
    577 /* Parameters:  softc(I) - pointer to soft context main structure           */
    578 /*              arg(I)   - pointer to local context to use                  */
    579 /*              op(I)    - pointer to lookup operatin data                  */
    580 /*                                                                          */
    581 /* Copy the current statistics out into user space, collecting pool list    */
    582 /* pointers as appropriate for later use.                                   */
    583 /* ------------------------------------------------------------------------ */
    584 static int
    585 ipf_pool_stats_get(ipf_main_softc_t *softc, void *arg, iplookupop_t *op)
    586 {
    587 	ipf_pool_softc_t *softp = arg;
    588 	ipf_pool_stat_t stats;
    589 	int unit, i, err = 0;
    590 
    591 	if (op->iplo_size != sizeof(ipf_pool_stat_t)) {
    592 		IPFERROR(70001);
    593 		return EINVAL;
    594 	}
    595 
    596 	bcopy((char *)&softp->ipf_pool_stats, (char *)&stats, sizeof(stats));
    597 	unit = op->iplo_unit;
    598 	if (unit == IPL_LOGALL) {
    599 		for (i = 0; i <= LOOKUP_POOL_MAX; i++)
    600 			stats.ipls_list[i] = softp->ipf_pool_list[i];
    601 	} else if (unit >= 0 && unit <= IPL_LOGMAX) {
    602 		unit++;						/* -1 => 0 */
    603 		if (op->iplo_name[0] != '\0')
    604 			stats.ipls_list[unit] = ipf_pool_exists(softp, unit - 1,
    605 								op->iplo_name);
    606 		else
    607 			stats.ipls_list[unit] = softp->ipf_pool_list[unit];
    608 	} else {
    609 		IPFERROR(70025);
    610 		err = EINVAL;
    611 	}
    612 	if (err == 0) {
    613 		err = COPYOUT(&stats, op->iplo_struct, sizeof(stats));
    614 		if (err != 0) {
    615 			IPFERROR(70026);
    616 			return EFAULT;
    617 		}
    618 	}
    619 	return 0;
    620 }
    621 
    622 
    623 /* ------------------------------------------------------------------------ */
    624 /* Function:    ipf_pool_exists                                             */
    625 /* Returns:     int      - 0 = success, else error                          */
    626 /* Parameters:  softp(I) - pointer to soft context pool information         */
    627 /*              unit(I)  - ipfilter device to which we are working on       */
    628 /*              name(I)  - name of the pool                                 */
    629 /*                                                                          */
    630 /* Find a matching pool inside the collection of pools for a particular     */
    631 /* device, indicated by the unit number.                                    */
    632 /* ------------------------------------------------------------------------ */
    633 static void *
    634 ipf_pool_exists(ipf_pool_softc_t *softp, int unit, char *name)
    635 {
    636 	ip_pool_t *p;
    637 	int i;
    638 
    639 	if (unit == IPL_LOGALL) {
    640 		for (i = 0; i <= LOOKUP_POOL_MAX; i++) {
    641 			for (p = softp->ipf_pool_list[i]; p != NULL;
    642 			     p = p->ipo_next) {
    643 				if (strncmp(p->ipo_name, name,
    644 					    sizeof(p->ipo_name)) == 0)
    645 					break;
    646 			}
    647 			if (p != NULL)
    648 				break;
    649 		}
    650 	} else {
    651 		for (p = softp->ipf_pool_list[unit + 1]; p != NULL;
    652 		     p = p->ipo_next)
    653 			if (strncmp(p->ipo_name, name,
    654 				    sizeof(p->ipo_name)) == 0)
    655 				break;
    656 	}
    657 	return p;
    658 }
    659 
    660 
    661 /* ------------------------------------------------------------------------ */
    662 /* Function:    ipf_pool_find                                               */
    663 /* Returns:     int    - 0 = success, else error                            */
    664 /* Parameters:  arg(I)  - pointer to local context to use                   */
    665 /*              unit(I) - ipfilter device to which we are working on        */
    666 /*              name(I)  - name of the pool                                 */
    667 /*                                                                          */
    668 /* Find a matching pool inside the collection of pools for a particular     */
    669 /* device, indicated by the unit number.  If it is marked for deletion then */
    670 /* pretend it does not exist.                                               */
    671 /* ------------------------------------------------------------------------ */
    672 static void *
    673 ipf_pool_find(void *arg, int unit, char *name)
    674 {
    675 	ipf_pool_softc_t *softp = arg;
    676 	ip_pool_t *p;
    677 
    678 	p = ipf_pool_exists(softp, unit, name);
    679 	if ((p != NULL) && (p->ipo_flags & IPOOL_DELETE))
    680 		return NULL;
    681 
    682 	return p;
    683 }
    684 
    685 
    686 /* ------------------------------------------------------------------------ */
    687 /* Function:    ipf_pool_select_add_ref                                     */
    688 /* Returns:     int - 0 = success, else error                               */
    689 /* Parameters:  arg(I)  - pointer to local context to use                   */
    690 /*              unit(I) - ipfilter device to which we are working on        */
    691 /*              name(I)  - name of the pool                                 */
    692 /*                                                                          */
    693 /* ------------------------------------------------------------------------ */
    694 static void *
    695 ipf_pool_select_add_ref(void *arg, int unit, char *name)
    696 {
    697 	ip_pool_t *p;
    698 
    699 	p = ipf_pool_find(arg, -1, name);
    700 	if (p == NULL)
    701 		p = ipf_pool_find(arg, unit, name);
    702 	if (p != NULL) {
    703 		ATOMIC_INC32(p->ipo_ref);
    704 	}
    705 	return p;
    706 }
    707 
    708 
    709 /* ------------------------------------------------------------------------ */
    710 /* Function:    ipf_pool_findeq                                             */
    711 /* Returns:     int     - 0 = success, else error                           */
    712 /* Parameters:  softp(I) - pointer to soft context pool information         */
    713 /*              ipo(I)  - pointer to the pool getting the new node.         */
    714 /*              addr(I) - pointer to address information to match on        */
    715 /*              mask(I) - pointer to the address mask to match              */
    716 /*                                                                          */
    717 /* Searches for an exact match of an entry in the pool.                     */
    718 /* ------------------------------------------------------------------------ */
    719 extern void printhostmask(int, u_32_t *, u_32_t *);
    720 static ip_pool_node_t *
    721 ipf_pool_findeq(ipf_pool_softc_t *softp, ip_pool_t *ipo, addrfamily_t *addr,
    722     addrfamily_t *mask)
    723 {
    724 	ipf_rdx_node_t *n;
    725 
    726 	n = ipo->ipo_head->lookup(ipo->ipo_head, addr, mask);
    727 	return (ip_pool_node_t *)n;
    728 }
    729 
    730 
    731 /* ------------------------------------------------------------------------ */
    732 /* Function:    ipf_pool_search                                             */
    733 /* Returns:     int     - 0 == +ve match, -1 == error, 1 == -ve/no match    */
    734 /* Parameters:  softc(I) - pointer to soft context main structure           */
    735 /*              tptr(I)    - pointer to the pool to search                  */
    736 /*              version(I) - IP protocol version (4 or 6)                   */
    737 /*              dptr(I)    - pointer to address information                 */
    738 /*              bytes(I)   - length of packet                               */
    739 /*                                                                          */
    740 /* Search the pool for a given address and return a search result.          */
    741 /* ------------------------------------------------------------------------ */
    742 static int
    743 ipf_pool_search(ipf_main_softc_t *softc, void *tptr, int ipversion, void *dptr,
    744     u_int bytes)
    745 {
    746 	ipf_rdx_node_t *rn;
    747 	ip_pool_node_t *m;
    748 	i6addr_t *addr;
    749 	addrfamily_t v;
    750 	ip_pool_t *ipo;
    751 	int rv;
    752 
    753 	ipo = tptr;
    754 	if (ipo == NULL)
    755 		return -1;
    756 
    757 	rv = 1;
    758 	m = NULL;
    759 	addr = (i6addr_t *)dptr;
    760 	bzero(&v, sizeof(v));
    761 
    762 	if (ipversion == 4) {
    763 		v.adf_family = AF_INET;
    764 		v.adf_len = offsetof(addrfamily_t, adf_addr) +
    765 			    sizeof(struct in_addr);
    766 		v.adf_addr.in4 = addr->in4;
    767 #ifdef USE_INET6
    768 	} else if (ipversion == 6) {
    769 		v.adf_family = AF_INET6;
    770 		v.adf_len = offsetof(addrfamily_t, adf_addr) +
    771 			    sizeof(struct in6_addr);
    772 		v.adf_addr.in6 = addr->in6;
    773 #endif
    774 	} else
    775 		return -1;
    776 
    777 	READ_ENTER(&softc->ipf_poolrw);
    778 
    779 	rn = ipo->ipo_head->matchaddr(ipo->ipo_head, &v);
    780 
    781 	if ((rn != NULL) && (rn->root == 0)) {
    782 		m = (ip_pool_node_t *)rn;
    783 		ipo->ipo_hits++;
    784 		m->ipn_bytes += bytes;
    785 		m->ipn_hits++;
    786 		rv = m->ipn_info;
    787 	}
    788 	RWLOCK_EXIT(&softc->ipf_poolrw);
    789 	return rv;
    790 }
    791 
    792 
    793 /* ------------------------------------------------------------------------ */
    794 /* Function:    ipf_pool_insert_node                                        */
    795 /* Returns:     int      - 0 = success, else error                          */
    796 /* Parameters:  softc(I) - pointer to soft context main structure           */
    797 /*              softp(I) - pointer to soft context pool information         */
    798 /*              ipo(I)   - pointer to the pool getting the new node.        */
    799 /*              node(I)  - structure with address/mask to add               */
    800 /* Locks:       WRITE(ipf_poolrw)                                           */
    801 /*                                                                          */
    802 /* Add another node to the pool given by ipo.  The three parameters passed  */
    803 /* in (addr, mask, info) shold all be stored in the node.                   */
    804 /* ------------------------------------------------------------------------ */
    805 static int
    806 ipf_pool_insert_node(ipf_main_softc_t *softc, ipf_pool_softc_t *softp,
    807     ip_pool_t *ipo, struct ip_pool_node *node)
    808 {
    809 	ipf_rdx_node_t *rn;
    810 	ip_pool_node_t *x;
    811 
    812 	if ((node->ipn_addr.adf_len > sizeof(*rn)) ||
    813 	    (node->ipn_addr.adf_len < 4)) {
    814 		IPFERROR(70003);
    815 		return EINVAL;
    816 	}
    817 
    818 	if ((node->ipn_mask.adf_len > sizeof(*rn)) ||
    819 	    (node->ipn_mask.adf_len < 4)) {
    820 		IPFERROR(70004);
    821 		return EINVAL;
    822 	}
    823 
    824 	KMALLOC(x, ip_pool_node_t *);
    825 	if (x == NULL) {
    826 		IPFERROR(70002);
    827 		return ENOMEM;
    828 	}
    829 
    830 	*x = *node;
    831 	bzero((char *)x->ipn_nodes, sizeof(x->ipn_nodes));
    832 	x->ipn_owner = ipo;
    833 	x->ipn_hits = 0;
    834 	x->ipn_next = NULL;
    835 	x->ipn_pnext = NULL;
    836 	x->ipn_dnext = NULL;
    837 	x->ipn_pdnext = NULL;
    838 
    839 	if (x->ipn_die != 0) {
    840 		/*
    841 		 * If the new node has a given expiration time, insert it
    842 		 * into the list of expiring nodes with the ones to be
    843 		 * removed first added to the front of the list. The
    844 		 * insertion is O(n) but it is kept sorted for quick scans
    845 		 * at expiration interval checks.
    846 		 */
    847 		ip_pool_node_t *n;
    848 
    849 		x->ipn_die = softc->ipf_ticks + IPF_TTLVAL(x->ipn_die);
    850 		for (n = softp->ipf_node_explist; n != NULL; n = n->ipn_dnext) {
    851 			if (x->ipn_die < n->ipn_die)
    852 				break;
    853 			if (n->ipn_dnext == NULL) {
    854 				/*
    855 				 * We've got to the last node and everything
    856 				 * wanted to be expired before this new node,
    857 				 * so we have to tack it on the end...
    858 				 */
    859 				n->ipn_dnext = x;
    860 				x->ipn_pdnext = &n->ipn_dnext;
    861 				n = NULL;
    862 				break;
    863 			}
    864 		}
    865 
    866 		if (softp->ipf_node_explist == NULL) {
    867 			softp->ipf_node_explist = x;
    868 			x->ipn_pdnext = &softp->ipf_node_explist;
    869 		} else if (n != NULL) {
    870 			x->ipn_dnext = n;
    871 			x->ipn_pdnext = n->ipn_pdnext;
    872 			n->ipn_pdnext = &x->ipn_dnext;
    873 		}
    874 	}
    875 
    876 	rn = ipo->ipo_head->addaddr(ipo->ipo_head, &x->ipn_addr, &x->ipn_mask,
    877 				    x->ipn_nodes);
    878 #ifdef	DEBUG_POOL
    879 	printf("Added %p at %p\n", x, rn);
    880 #endif
    881 
    882 	if (rn == NULL) {
    883 		KFREE(x);
    884 		IPFERROR(70005);
    885 		return ENOMEM;
    886 	}
    887 
    888 	x->ipn_ref = 1;
    889 	x->ipn_pnext = ipo->ipo_tail;
    890 	*ipo->ipo_tail = x;
    891 	ipo->ipo_tail = &x->ipn_next;
    892 
    893 	softp->ipf_pool_stats.ipls_nodes++;
    894 
    895 	return 0;
    896 }
    897 
    898 
    899 /* ------------------------------------------------------------------------ */
    900 /* Function:    ipf_pool_create                                             */
    901 /* Returns:     int      - 0 = success, else error                          */
    902 /* Parameters:  softc(I) - pointer to soft context main structure           */
    903 /*              softp(I) - pointer to soft context pool information         */
    904 /*              op(I)    - pointer to iplookup struct with call details     */
    905 /* Locks:       WRITE(ipf_poolrw)                                           */
    906 /*                                                                          */
    907 /* Creates a new group according to the paramters passed in via the         */
    908 /* iplookupop structure.  Does not check to see if the group already exists */
    909 /* when being inserted - assume this has already been done.  If the pool is */
    910 /* marked as being anonymous, give it a new, unique, identifier.  Call any  */
    911 /* other functions required to initialise the structure.                    */
    912 /*                                                                          */
    913 /* If the structure is flagged for deletion then reset the flag and return, */
    914 /* as this likely means we've tried to free a pool that is in use (flush)   */
    915 /* and now want to repopulate it with "new" data.                           */
    916 /* ------------------------------------------------------------------------ */
    917 static int
    918 ipf_pool_create(ipf_main_softc_t *softc, ipf_pool_softc_t *softp,
    919     iplookupop_t *op)
    920 {
    921 	char name[FR_GROUPLEN];
    922 	int poolnum, unit;
    923 	ip_pool_t *h;
    924 
    925 	unit = op->iplo_unit;
    926 
    927 	if ((op->iplo_arg & LOOKUP_ANON) == 0) {
    928 		h = ipf_pool_exists(softp, unit, op->iplo_name);
    929 		if (h != NULL) {
    930 			if ((h->ipo_flags & IPOOL_DELETE) == 0) {
    931 				IPFERROR(70006);
    932 				return EEXIST;
    933 			}
    934 			h->ipo_flags &= ~IPOOL_DELETE;
    935 			return 0;
    936 		}
    937 	}
    938 
    939 	KMALLOC(h, ip_pool_t *);
    940 	if (h == NULL) {
    941 		IPFERROR(70007);
    942 		return ENOMEM;
    943 	}
    944 	bzero(h, sizeof(*h));
    945 
    946 	if (ipf_rx_inithead(softp->ipf_radix, &h->ipo_head) != 0) {
    947 		KFREE(h);
    948 		IPFERROR(70008);
    949 		return ENOMEM;
    950 	}
    951 
    952 	if ((op->iplo_arg & LOOKUP_ANON) != 0) {
    953 		ip_pool_t *p;
    954 
    955 		h->ipo_flags |= IPOOL_ANON;
    956 		poolnum = LOOKUP_ANON;
    957 
    958 #if defined(SNPRINTF) && defined(_KERNEL)
    959 		SNPRINTF(name, sizeof(name), "%x", poolnum);
    960 #else
    961 		(void)sprintf(name, "%x", poolnum);
    962 #endif
    963 
    964 		for (p = softp->ipf_pool_list[unit + 1]; p != NULL; ) {
    965 			if (strncmp(name, p->ipo_name,
    966 				    sizeof(p->ipo_name)) == 0) {
    967 				poolnum++;
    968 #if defined(SNPRINTF) && defined(_KERNEL)
    969 				SNPRINTF(name, sizeof(name), "%x", poolnum);
    970 #else
    971 				(void)sprintf(name, "%x", poolnum);
    972 #endif
    973 				p = softp->ipf_pool_list[unit + 1];
    974 			} else
    975 				p = p->ipo_next;
    976 		}
    977 
    978 		(void)strncpy(h->ipo_name, name, sizeof(h->ipo_name));
    979 		(void)strncpy(op->iplo_name, name, sizeof(op->iplo_name));
    980 	} else {
    981 		(void)strncpy(h->ipo_name, op->iplo_name, sizeof(h->ipo_name));
    982 	}
    983 
    984 	h->ipo_radix = softp->ipf_radix;
    985 	h->ipo_ref = 1;
    986 	h->ipo_list = NULL;
    987 	h->ipo_tail = &h->ipo_list;
    988 	h->ipo_unit = unit;
    989 	h->ipo_next = softp->ipf_pool_list[unit + 1];
    990 	if (softp->ipf_pool_list[unit + 1] != NULL)
    991 		softp->ipf_pool_list[unit + 1]->ipo_pnext = &h->ipo_next;
    992 	h->ipo_pnext = &softp->ipf_pool_list[unit + 1];
    993 	softp->ipf_pool_list[unit + 1] = h;
    994 
    995 	softp->ipf_pool_stats.ipls_pools++;
    996 
    997 	return 0;
    998 }
    999 
   1000 
   1001 /* ------------------------------------------------------------------------ */
   1002 /* Function:    ipf_pool_remove_node                                        */
   1003 /* Returns:     int      - 0 = success, else error                          */
   1004 /* Parameters:  softc(I) - pointer to soft context main structure           */
   1005 /*              ipo(I)   - pointer to the pool to remove the node from.     */
   1006 /*              ipe(I)   - address being deleted as a node                  */
   1007 /* Locks:       WRITE(ipf_poolrw)                                           */
   1008 /*                                                                          */
   1009 /* Remove a node from the pool given by ipo.                                */
   1010 /* ------------------------------------------------------------------------ */
   1011 static int
   1012 ipf_pool_remove_node(ipf_main_softc_t *softc, ipf_pool_softc_t *softp,
   1013 	ip_pool_t *ipo, ip_pool_node_t *ipe)
   1014 {
   1015 	void *ptr;
   1016 
   1017 	if (ipo->ipo_tail == &ipe->ipn_next)
   1018 		ipo->ipo_tail = ipe->ipn_pnext;
   1019 
   1020 	if (ipe->ipn_pnext != NULL)
   1021 		*ipe->ipn_pnext = ipe->ipn_next;
   1022 	if (ipe->ipn_next != NULL)
   1023 		ipe->ipn_next->ipn_pnext = ipe->ipn_pnext;
   1024 
   1025 	if (ipe->ipn_pdnext != NULL)
   1026 		*ipe->ipn_pdnext = ipe->ipn_dnext;
   1027 	if (ipe->ipn_dnext != NULL)
   1028 		ipe->ipn_dnext->ipn_pdnext = ipe->ipn_pdnext;
   1029 
   1030 	ptr = ipo->ipo_head->deladdr(ipo->ipo_head, &ipe->ipn_addr,
   1031 				     &ipe->ipn_mask);
   1032 
   1033 	if (ptr != NULL) {
   1034 		ipf_pool_node_deref(softp, ipe);
   1035 		return 0;
   1036 	}
   1037 	IPFERROR(70027);
   1038 	return ESRCH;
   1039 }
   1040 
   1041 
   1042 /* ------------------------------------------------------------------------ */
   1043 /* Function:    ipf_pool_destroy                                            */
   1044 /* Returns:     int    - 0 = success, else error                            */
   1045 /* Parameters:  softc(I) - pointer to soft context main structure           */
   1046 /*              softp(I) - pointer to soft context pool information         */
   1047 /*              unit(I)  - ipfilter device to which we are working on      */
   1048 /*              name(I)  - name of the pool                                 */
   1049 /* Locks:       WRITE(ipf_poolrw) or WRITE(ipf_global)                      */
   1050 /*                                                                          */
   1051 /* Search for a pool using paramters passed in and if it's not otherwise    */
   1052 /* busy, free it.  If it is busy, clear all of its nodes, mark it for being */
   1053 /* deleted and return an error saying it is busy.                           */
   1054 /*                                                                          */
   1055 /* NOTE: Because this function is called out of ipfdetach() where ipf_poolrw*/
   1056 /* may not be initialised, we can't use an ASSERT to enforce the locking    */
   1057 /* assertion that one of the two (ipf_poolrw,ipf_global) is held.           */
   1058 /* ------------------------------------------------------------------------ */
   1059 static int
   1060 ipf_pool_destroy(ipf_main_softc_t *softc, ipf_pool_softc_t *softp, int unit,
   1061     char *name)
   1062 {
   1063 	ip_pool_t *ipo;
   1064 
   1065 	ipo = ipf_pool_exists(softp, unit, name);
   1066 	if (ipo == NULL) {
   1067 		IPFERROR(70009);
   1068 		return ESRCH;
   1069 	}
   1070 
   1071 	if (ipo->ipo_ref != 1) {
   1072 		ipf_pool_clearnodes(softc, softp, ipo);
   1073 		ipo->ipo_flags |= IPOOL_DELETE;
   1074 		return 0;
   1075 	}
   1076 
   1077 	ipf_pool_free(softc, softp, ipo);
   1078 	return 0;
   1079 }
   1080 
   1081 
   1082 /* ------------------------------------------------------------------------ */
   1083 /* Function:    ipf_pool_flush                                              */
   1084 /* Returns:     int    - number of pools deleted                            */
   1085 /* Parameters:  softc(I) - pointer to soft context main structure           */
   1086 /*              arg(I)   - pointer to local context to use                  */
   1087 /*              fp(I)    - which pool(s) to flush                           */
   1088 /* Locks:       WRITE(ipf_poolrw) or WRITE(ipf_global)                      */
   1089 /*                                                                          */
   1090 /* Free all pools associated with the device that matches the unit number   */
   1091 /* passed in with operation.                                                */
   1092 /*                                                                          */
   1093 /* NOTE: Because this function is called out of ipfdetach() where ipf_poolrw*/
   1094 /* may not be initialised, we can't use an ASSERT to enforce the locking    */
   1095 /* assertion that one of the two (ipf_poolrw,ipf_global) is held.           */
   1096 /* ------------------------------------------------------------------------ */
   1097 static size_t
   1098 ipf_pool_flush(ipf_main_softc_t *softc, void *arg, iplookupflush_t *fp)
   1099 {
   1100 	ipf_pool_softc_t *softp = arg;
   1101 	int i, num = 0, unit, err;
   1102 	ip_pool_t *p, *q;
   1103 
   1104 	unit = fp->iplf_unit;
   1105 	for (i = -1; i <= IPL_LOGMAX; i++) {
   1106 		if (unit != IPLT_ALL && i != unit)
   1107 			continue;
   1108 		for (q = softp->ipf_pool_list[i + 1]; (p = q) != NULL; ) {
   1109 			q = p->ipo_next;
   1110 			err = ipf_pool_destroy(softc, softp, i, p->ipo_name);
   1111 			if (err == 0)
   1112 				num++;
   1113 		}
   1114 	}
   1115 	return num;
   1116 }
   1117 
   1118 
   1119 /* ------------------------------------------------------------------------ */
   1120 /* Function:    ipf_pool_free                                               */
   1121 /* Returns:     void                                                        */
   1122 /* Parameters:  softc(I) - pointer to soft context main structure           */
   1123 /*              softp(I) - pointer to soft context pool information         */
   1124 /*              ipo(I) - pointer to pool structure                          */
   1125 /* Locks:       WRITE(ipf_poolrw) or WRITE(ipf_global)                      */
   1126 /*                                                                          */
   1127 /* Deletes the pool strucutre passed in from the list of pools and deletes  */
   1128 /* all of the address information stored in it, including any tree data     */
   1129 /* structures also allocated.                                               */
   1130 /*                                                                          */
   1131 /* NOTE: Because this function is called out of ipfdetach() where ipf_poolrw*/
   1132 /* may not be initialised, we can't use an ASSERT to enforce the locking    */
   1133 /* assertion that one of the two (ipf_poolrw,ipf_global) is held.           */
   1134 /* ------------------------------------------------------------------------ */
   1135 static void
   1136 ipf_pool_free(ipf_main_softc_t *softc, ipf_pool_softc_t *softp, ip_pool_t *ipo)
   1137 {
   1138 
   1139 	ipf_pool_clearnodes(softc, softp, ipo);
   1140 
   1141 	if (ipo->ipo_next != NULL)
   1142 		ipo->ipo_next->ipo_pnext = ipo->ipo_pnext;
   1143 	*ipo->ipo_pnext = ipo->ipo_next;
   1144 	ipf_rx_freehead(ipo->ipo_head);
   1145 	KFREE(ipo);
   1146 
   1147 	softp->ipf_pool_stats.ipls_pools--;
   1148 }
   1149 
   1150 
   1151 /* ------------------------------------------------------------------------ */
   1152 /* Function:    ipf_pool_clearnodes                                         */
   1153 /* Returns:     void                                                        */
   1154 /* Parameters:  softc(I) - pointer to soft context main structure           */
   1155 /*              softp(I) - pointer to soft context pool information         */
   1156 /*              ipo(I)   - pointer to pool structure                        */
   1157 /* Locks:       WRITE(ipf_poolrw) or WRITE(ipf_global)                      */
   1158 /*                                                                          */
   1159 /* Deletes all nodes stored in a pool structure.                            */
   1160 /* ------------------------------------------------------------------------ */
   1161 static void
   1162 ipf_pool_clearnodes(ipf_main_softc_t *softc, ipf_pool_softc_t *softp,
   1163 	ip_pool_t *ipo)
   1164 {
   1165 	ip_pool_node_t *n, **next;
   1166 
   1167 	for (next = &ipo->ipo_list; (n = *next) != NULL; )
   1168 		ipf_pool_remove_node(softc, softp, ipo, n);
   1169 
   1170 	ipo->ipo_list = NULL;
   1171 }
   1172 
   1173 
   1174 /* ------------------------------------------------------------------------ */
   1175 /* Function:    ipf_pool_deref                                              */
   1176 /* Returns:     void                                                        */
   1177 /* Parameters:  softc(I) - pointer to soft context main structure           */
   1178 /*              arg(I)   - pointer to local context to use                  */
   1179 /*              pool(I)  - pointer to pool structure                        */
   1180 /* Locks:       WRITE(ipf_poolrw)                                           */
   1181 /*                                                                          */
   1182 /* Drop the number of known references to this pool structure by one and if */
   1183 /* we arrive at zero known references, free it.                             */
   1184 /* ------------------------------------------------------------------------ */
   1185 static int
   1186 ipf_pool_deref(ipf_main_softc_t *softc, void *arg, void *pool)
   1187 {
   1188 	ip_pool_t *ipo = pool;
   1189 
   1190 	ipo->ipo_ref--;
   1191 
   1192 	if (ipo->ipo_ref == 0)
   1193 		ipf_pool_free(softc, arg, ipo);
   1194 
   1195 	else if ((ipo->ipo_ref == 1) && (ipo->ipo_flags & IPOOL_DELETE))
   1196 		ipf_pool_destroy(softc, arg, ipo->ipo_unit, ipo->ipo_name);
   1197 
   1198 	return 0;
   1199 }
   1200 
   1201 
   1202 /* ------------------------------------------------------------------------ */
   1203 /* Function:    ipf_pool_node_deref                                         */
   1204 /* Returns:     void                                                        */
   1205 /* Parameters:  softp(I) - pointer to soft context pool information         */
   1206 /*              ipn(I)   - pointer to pool structure                        */
   1207 /* Locks:       WRITE(ipf_poolrw)                                           */
   1208 /*                                                                          */
   1209 /* Drop a reference to the pool node passed in and if we're the last, free  */
   1210 /* it all up and adjust the stats accordingly.                              */
   1211 /* ------------------------------------------------------------------------ */
   1212 static void
   1213 ipf_pool_node_deref(ipf_pool_softc_t *softp, ip_pool_node_t *ipn)
   1214 {
   1215 
   1216 	ipn->ipn_ref--;
   1217 
   1218 	if (ipn->ipn_ref == 0) {
   1219 		KFREE(ipn);
   1220 		softp->ipf_pool_stats.ipls_nodes--;
   1221 	}
   1222 }
   1223 
   1224 
   1225 /* ------------------------------------------------------------------------ */
   1226 /* Function:    ipf_pool_iter_next                                          */
   1227 /* Returns:     void                                                        */
   1228 /* Parameters:  softc(I) - pointer to soft context main structure           */
   1229 /*              arg(I)   - pointer to local context to use                  */
   1230 /*              token(I) - pointer to pool structure                        */
   1231 /*              ilp(IO)  - pointer to pool iterating structure              */
   1232 /*                                                                          */
   1233 /* ------------------------------------------------------------------------ */
   1234 static int
   1235 ipf_pool_iter_next(ipf_main_softc_t *softc, void *arg, ipftoken_t *token,
   1236     ipflookupiter_t *ilp)
   1237 {
   1238 	ipf_pool_softc_t *softp = arg;
   1239 	ip_pool_node_t *node, zn, *nextnode;
   1240 	ip_pool_t *ipo, zp, *nextipo;
   1241 	void *pnext;
   1242 	int err;
   1243 
   1244 	err = 0;
   1245 	node = NULL;
   1246 	nextnode = NULL;
   1247 	ipo = NULL;
   1248 	nextipo = NULL;
   1249 
   1250 	READ_ENTER(&softc->ipf_poolrw);
   1251 
   1252 	switch (ilp->ili_otype)
   1253 	{
   1254 	case IPFLOOKUPITER_LIST :
   1255 		ipo = token->ipt_data;
   1256 		if (ipo == NULL) {
   1257 			nextipo = softp->ipf_pool_list[(int)ilp->ili_unit + 1];
   1258 		} else {
   1259 			nextipo = ipo->ipo_next;
   1260 		}
   1261 
   1262 		if (nextipo != NULL) {
   1263 			ATOMIC_INC32(nextipo->ipo_ref);
   1264 			token->ipt_data = nextipo;
   1265 		} else {
   1266 			bzero((char *)&zp, sizeof(zp));
   1267 			nextipo = &zp;
   1268 			token->ipt_data = NULL;
   1269 		}
   1270 		pnext = nextipo->ipo_next;
   1271 		break;
   1272 
   1273 	case IPFLOOKUPITER_NODE :
   1274 		node = token->ipt_data;
   1275 		if (node == NULL) {
   1276 			ipo = ipf_pool_exists(arg, ilp->ili_unit,
   1277 					      ilp->ili_name);
   1278 			if (ipo == NULL) {
   1279 				IPFERROR(70010);
   1280 				err = ESRCH;
   1281 			} else {
   1282 				nextnode = ipo->ipo_list;
   1283 				ipo = NULL;
   1284 			}
   1285 		} else {
   1286 			nextnode = node->ipn_next;
   1287 		}
   1288 
   1289 		if (nextnode != NULL) {
   1290 			ATOMIC_INC32(nextnode->ipn_ref);
   1291 			token->ipt_data = nextnode;
   1292 		} else {
   1293 			bzero((char *)&zn, sizeof(zn));
   1294 			nextnode = &zn;
   1295 			token->ipt_data = NULL;
   1296 		}
   1297 		pnext = nextnode->ipn_next;
   1298 		break;
   1299 
   1300 	default :
   1301 		IPFERROR(70011);
   1302 		pnext = NULL;
   1303 		err = EINVAL;
   1304 		break;
   1305 	}
   1306 
   1307 	RWLOCK_EXIT(&softc->ipf_poolrw);
   1308 	if (err != 0)
   1309 		return err;
   1310 
   1311 	switch (ilp->ili_otype)
   1312 	{
   1313 	case IPFLOOKUPITER_LIST :
   1314 		err = COPYOUT(nextipo, ilp->ili_data, sizeof(*nextipo));
   1315 		if (err != 0)  {
   1316 			IPFERROR(70012);
   1317 			err = EFAULT;
   1318 		}
   1319 		if (ipo != NULL) {
   1320 			WRITE_ENTER(&softc->ipf_poolrw);
   1321 			ipf_pool_deref(softc, softp, ipo);
   1322 			RWLOCK_EXIT(&softc->ipf_poolrw);
   1323 		}
   1324 		break;
   1325 
   1326 	case IPFLOOKUPITER_NODE :
   1327 		err = COPYOUT(nextnode, ilp->ili_data, sizeof(*nextnode));
   1328 		if (err != 0) {
   1329 			IPFERROR(70013);
   1330 			err = EFAULT;
   1331 		}
   1332 		if (node != NULL) {
   1333 			WRITE_ENTER(&softc->ipf_poolrw);
   1334 			ipf_pool_node_deref(softp, node);
   1335 			RWLOCK_EXIT(&softc->ipf_poolrw);
   1336 		}
   1337 		break;
   1338 	}
   1339 	if (pnext == NULL)
   1340 		ipf_token_mark_complete(token);
   1341 
   1342 	return err;
   1343 }
   1344 
   1345 
   1346 /* ------------------------------------------------------------------------ */
   1347 /* Function:    ipf_pool_iterderef                                          */
   1348 /* Returns:     void                                                        */
   1349 /* Parameters:  softc(I) - pointer to soft context main structure           */
   1350 /*              arg(I)   - pointer to local context to use                  */
   1351 /*              unit(I)  - ipfilter device to which we are working on       */
   1352 /* Locks:       WRITE(ipf_poolrw)                                           */
   1353 /*                                                                          */
   1354 /* ------------------------------------------------------------------------ */
   1355 static int
   1356 ipf_pool_iter_deref(ipf_main_softc_t *softc, void *arg, int otype, int unit,
   1357     void *data)
   1358 {
   1359 	ipf_pool_softc_t *softp = arg;
   1360 
   1361 	if (data == NULL)
   1362 		return EINVAL;
   1363 
   1364 	if (unit < 0 || unit > IPL_LOGMAX)
   1365 		return EINVAL;
   1366 
   1367 	switch (otype)
   1368 	{
   1369 	case IPFLOOKUPITER_LIST :
   1370 		ipf_pool_deref(softc, softp, (ip_pool_t *)data);
   1371 		break;
   1372 
   1373 	case IPFLOOKUPITER_NODE :
   1374 		ipf_pool_node_deref(softp, (ip_pool_node_t *)data);
   1375 		break;
   1376 	default :
   1377 		break;
   1378 	}
   1379 
   1380 	return 0;
   1381 }
   1382 
   1383 
   1384 /* ------------------------------------------------------------------------ */
   1385 /* Function:    ipf_pool_expire                                             */
   1386 /* Returns:     Nil                                                         */
   1387 /* Parameters:  softc(I) - pointer to soft context main structure           */
   1388 /*              arg(I)   - pointer to local context to use                  */
   1389 /*                                                                          */
   1390 /* At present this function exists just to support temporary addition of    */
   1391 /* nodes to the address pool.                                               */
   1392 /* ------------------------------------------------------------------------ */
   1393 static void
   1394 ipf_pool_expire(ipf_main_softc_t *softc, void *arg)
   1395 {
   1396 	ipf_pool_softc_t *softp = arg;
   1397 	ip_pool_node_t *n;
   1398 
   1399 	while ((n = softp->ipf_node_explist) != NULL) {
   1400 		/*
   1401 		 * Because the list is kept sorted on insertion, the fist
   1402 		 * one that dies in the future means no more work to do.
   1403 		 */
   1404 		if (n->ipn_die > softc->ipf_ticks)
   1405 			break;
   1406 		ipf_pool_remove_node(softc, softp, n->ipn_owner, n);
   1407 	}
   1408 }
   1409 
   1410 
   1411 
   1412 
   1413 #ifndef _KERNEL
   1414 void
   1415 ipf_pool_dump(softc, arg)
   1416 	ipf_main_softc_t *softc;
   1417 	void *arg;
   1418 {
   1419 	ipf_pool_softc_t *softp = arg;
   1420 	ip_pool_t *ipl;
   1421 	int i;
   1422 
   1423 	printf("List of configured pools\n");
   1424 	for (i = 0; i <= LOOKUP_POOL_MAX; i++)
   1425 		for (ipl = softp->ipf_pool_list[i]; ipl != NULL;
   1426 		     ipl = ipl->ipo_next)
   1427 			printpool(ipl, bcopywrap, NULL, opts, NULL);
   1428 }
   1429 #endif
   1430