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