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