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