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