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