1145516Sdarrenr/*
2255332Scy * Copyright (C) 2012 by Darren Reed.
3145516Sdarrenr *
4145516Sdarrenr * See the IPFILTER.LICENCE file for details on licencing.
5145516Sdarrenr */
6145516Sdarrenr#if defined(KERNEL) || defined(_KERNEL)
7145516Sdarrenr# undef KERNEL
8145516Sdarrenr# undef _KERNEL
9145516Sdarrenr# define        KERNEL	1
10145516Sdarrenr# define        _KERNEL	1
11145516Sdarrenr#endif
12145516Sdarrenr#if defined(__osf__)
13145516Sdarrenr# define _PROTO_NET_H_
14145516Sdarrenr#endif
15145516Sdarrenr#include <sys/errno.h>
16145516Sdarrenr#include <sys/types.h>
17145516Sdarrenr#include <sys/param.h>
18145516Sdarrenr#include <sys/file.h>
19145516Sdarrenr#if !defined(_KERNEL) && !defined(__KERNEL__)
20145516Sdarrenr# include <stdio.h>
21145516Sdarrenr# include <stdlib.h>
22145516Sdarrenr# include <string.h>
23145516Sdarrenr# define _KERNEL
24145516Sdarrenr# ifdef __OpenBSD__
25145516Sdarrenrstruct file;
26145516Sdarrenr# endif
27145516Sdarrenr# include <sys/uio.h>
28145516Sdarrenr# undef _KERNEL
29145516Sdarrenr#else
30145516Sdarrenr# include <sys/systm.h>
31145516Sdarrenr# if defined(NetBSD) && (__NetBSD_Version__ >= 104000000)
32145516Sdarrenr#  include <sys/proc.h>
33145516Sdarrenr# endif
34145516Sdarrenr#endif
35145516Sdarrenr#include <sys/time.h>
36255332Scy#if defined(_KERNEL) && !defined(SOLARIS2)
37145516Sdarrenr# include <sys/mbuf.h>
38145516Sdarrenr#endif
39145516Sdarrenr#if defined(__SVR4) || defined(__svr4__)
40145516Sdarrenr# include <sys/byteorder.h>
41145516Sdarrenr# ifdef _KERNEL
42145516Sdarrenr#  include <sys/dditypes.h>
43145516Sdarrenr# endif
44145516Sdarrenr# include <sys/stream.h>
45145516Sdarrenr# include <sys/kmem.h>
46145516Sdarrenr#endif
47145516Sdarrenr#if defined(__FreeBSD_version) && (__FreeBSD_version >= 300000)
48145516Sdarrenr# include <sys/malloc.h>
49145516Sdarrenr#endif
50145516Sdarrenr
51255332Scy#include <sys/socket.h>
52145516Sdarrenr#include <net/if.h>
53145516Sdarrenr#include <netinet/in.h>
54255332Scy#if !defined(_KERNEL)
55255332Scy# include "ipf.h"
56255332Scy#endif
57145516Sdarrenr
58145516Sdarrenr#include "netinet/ip_compat.h"
59145516Sdarrenr#include "netinet/ip_fil.h"
60145516Sdarrenr#include "netinet/ip_pool.h"
61255332Scy#include "netinet/radix_ipf.h"
62145516Sdarrenr
63145516Sdarrenr/* END OF INCLUDES */
64145516Sdarrenr
65145516Sdarrenr#if !defined(lint)
66145516Sdarrenrstatic const char sccsid[] = "@(#)ip_fil.c	2.41 6/5/96 (C) 1993-2000 Darren Reed";
67255332Scystatic const char rcsid[] = "@(#)$Id$";
68145516Sdarrenr#endif
69145516Sdarrenr
70255332Scytypedef struct ipf_pool_softc_s {
71255332Scy	void		*ipf_radix;
72255332Scy	ip_pool_t	*ipf_pool_list[LOOKUP_POOL_SZ];
73255332Scy	ipf_pool_stat_t	ipf_pool_stats;
74255332Scy	ip_pool_node_t	*ipf_node_explist;
75255332Scy} ipf_pool_softc_t;
76145516Sdarrenr
77145516Sdarrenr
78255332Scystatic void ipf_pool_clearnodes __P((ipf_main_softc_t *, ipf_pool_softc_t *,
79255332Scy				     ip_pool_t *));
80255332Scystatic int ipf_pool_create __P((ipf_main_softc_t *, ipf_pool_softc_t *, iplookupop_t *));
81255332Scystatic int ipf_pool_deref __P((ipf_main_softc_t *, void *, void *));
82255332Scystatic int ipf_pool_destroy __P((ipf_main_softc_t *, ipf_pool_softc_t *, int, char *));
83255332Scystatic void *ipf_pool_exists __P((ipf_pool_softc_t *, int, char *));
84255332Scystatic void *ipf_pool_find __P((void *, int, char *));
85255332Scystatic ip_pool_node_t *ipf_pool_findeq __P((ipf_pool_softc_t *, ip_pool_t *,
86255332Scy					    addrfamily_t *, addrfamily_t *));
87255332Scystatic void ipf_pool_free __P((ipf_main_softc_t *, ipf_pool_softc_t *,
88255332Scy			       ip_pool_t *));
89255332Scystatic int ipf_pool_insert_node __P((ipf_main_softc_t *, ipf_pool_softc_t *,
90255332Scy				     ip_pool_t *, struct ip_pool_node *));
91255332Scystatic int ipf_pool_iter_deref __P((ipf_main_softc_t *, void *, int, int, void *));
92255332Scystatic int ipf_pool_iter_next __P((ipf_main_softc_t *,  void *, ipftoken_t *,
93255332Scy				   ipflookupiter_t *));
94255332Scystatic size_t ipf_pool_flush __P((ipf_main_softc_t *, void *, iplookupflush_t *));
95255332Scystatic int ipf_pool_node_add __P((ipf_main_softc_t *, void *, iplookupop_t *,
96255332Scy				  int));
97255332Scystatic int ipf_pool_node_del __P((ipf_main_softc_t *, void *, iplookupop_t *,
98255332Scy				  int));
99255332Scystatic void ipf_pool_node_deref __P((ipf_pool_softc_t *, ip_pool_node_t *));
100255332Scystatic int ipf_pool_remove_node __P((ipf_main_softc_t *, ipf_pool_softc_t *,
101255332Scy				     ip_pool_t *, ip_pool_node_t *));
102255332Scystatic int ipf_pool_search __P((ipf_main_softc_t *, void *, int,
103255332Scy				void *, u_int));
104255332Scystatic void *ipf_pool_soft_create __P((ipf_main_softc_t *));
105255332Scystatic void ipf_pool_soft_destroy __P((ipf_main_softc_t *, void *));
106255332Scystatic void ipf_pool_soft_fini __P((ipf_main_softc_t *, void *));
107255332Scystatic int ipf_pool_soft_init __P((ipf_main_softc_t *, void *));
108255332Scystatic int ipf_pool_stats_get __P((ipf_main_softc_t *, void *, iplookupop_t *));
109255332Scystatic int ipf_pool_table_add __P((ipf_main_softc_t *, void *, iplookupop_t *));
110255332Scystatic int ipf_pool_table_del __P((ipf_main_softc_t *, void *, iplookupop_t *));
111255332Scystatic void *ipf_pool_select_add_ref __P((void *, int, char *));
112255332Scystatic void ipf_pool_expire __P((ipf_main_softc_t *, void *));
113170263Sdarrenr
114255332Scyipf_lookup_t ipf_pool_backend = {
115255332Scy	IPLT_POOL,
116255332Scy	ipf_pool_soft_create,
117255332Scy	ipf_pool_soft_destroy,
118255332Scy	ipf_pool_soft_init,
119255332Scy	ipf_pool_soft_fini,
120255332Scy	ipf_pool_search,
121255332Scy	ipf_pool_flush,
122255332Scy	ipf_pool_iter_deref,
123255332Scy	ipf_pool_iter_next,
124255332Scy	ipf_pool_node_add,
125255332Scy	ipf_pool_node_del,
126255332Scy	ipf_pool_stats_get,
127255332Scy	ipf_pool_table_add,
128255332Scy	ipf_pool_table_del,
129255332Scy	ipf_pool_deref,
130255332Scy	ipf_pool_find,
131255332Scy	ipf_pool_select_add_ref,
132255332Scy	NULL,
133255332Scy	ipf_pool_expire,
134255332Scy	NULL
135255332Scy};
136145516Sdarrenr
137145516Sdarrenr
138145516Sdarrenr#ifdef TEST_POOL
139145516Sdarrenrvoid treeprint __P((ip_pool_t *));
140145516Sdarrenr
141145516Sdarrenrint
142145516Sdarrenrmain(argc, argv)
143145516Sdarrenr	int argc;
144145516Sdarrenr	char *argv[];
145145516Sdarrenr{
146255332Scy	ip_pool_node_t node;
147145516Sdarrenr	addrfamily_t a, b;
148145516Sdarrenr	iplookupop_t op;
149145516Sdarrenr	ip_pool_t *ipo;
150145516Sdarrenr	i6addr_t ip;
151145516Sdarrenr
152255332Scy	RWLOCK_INIT(softc->ipf_poolrw, "poolrw");
153255332Scy	ipf_pool_init();
154145516Sdarrenr
155145516Sdarrenr	bzero((char *)&ip, sizeof(ip));
156145516Sdarrenr	bzero((char *)&op, sizeof(op));
157255332Scy	bzero((char *)&node, sizeof(node));
158145516Sdarrenr	strcpy(op.iplo_name, "0");
159145516Sdarrenr
160255332Scy	if (ipf_pool_create(&op) == 0)
161255332Scy		ipo = ipf_pool_exists(0, "0");
162145516Sdarrenr
163255332Scy	node.ipn_addr.adf_family = AF_INET;
164145516Sdarrenr
165255332Scy	node.ipn_addr.adf_addr.in4.s_addr = 0x0a010203;
166255332Scy	node.ipn_mask.adf_addr.in4.s_addr = 0xffffffff;
167255332Scy	node.ipn_info = 1;
168255332Scy	ipf_pool_insert_node(ipo, &node);
169145516Sdarrenr
170255332Scy	node.ipn_addr.adf_addr.in4.s_addr = 0x0a000000;
171255332Scy	node.ipn_mask.adf_addr.in4.s_addr = 0xff000000;
172255332Scy	node.ipn_info = 0;
173255332Scy	ipf_pool_insert_node(ipo, &node);
174145516Sdarrenr
175255332Scy	node.ipn_addr.adf_addr.in4.s_addr = 0x0a010100;
176255332Scy	node.ipn_mask.adf_addr.in4.s_addr = 0xffffff00;
177255332Scy	node.ipn_info = 1;
178255332Scy	ipf_pool_insert_node(ipo, &node);
179145516Sdarrenr
180255332Scy	node.ipn_addr.adf_addr.in4.s_addr = 0x0a010200;
181255332Scy	node.ipn_mask.adf_addr.in4.s_addr = 0xffffff00;
182255332Scy	node.ipn_info = 0;
183255332Scy	ipf_pool_insert_node(ipo, &node);
184145516Sdarrenr
185255332Scy	node.ipn_addr.adf_addr.in4.s_addr = 0x0a010000;
186255332Scy	node.ipn_mask.adf_addr.in4.s_addr = 0xffff0000;
187255332Scy	node.ipn_info = 1;
188255332Scy	ipf_pool_insert_node(ipo, &node);
189255332Scy
190255332Scy	node.ipn_addr.adf_addr.in4.s_addr = 0x0a01020f;
191255332Scy	node.ipn_mask.adf_addr.in4.s_addr = 0xffffffff;
192255332Scy	node.ipn_info = 1;
193255332Scy	ipf_pool_insert_node(ipo, &node);
194145516Sdarrenr#ifdef	DEBUG_POOL
195255332Scy	treeprint(ipo);
196145516Sdarrenr#endif
197145516Sdarrenr	ip.in4.s_addr = 0x0a00aabb;
198145516Sdarrenr	printf("search(%#x) = %d (0)\n", ip.in4.s_addr,
199255332Scy		ipf_pool_search(ipo, 4, &ip, 1));
200145516Sdarrenr
201145516Sdarrenr	ip.in4.s_addr = 0x0a000001;
202145516Sdarrenr	printf("search(%#x) = %d (0)\n", ip.in4.s_addr,
203255332Scy		ipf_pool_search(ipo, 4, &ip, 1));
204145516Sdarrenr
205145516Sdarrenr	ip.in4.s_addr = 0x0a000101;
206145516Sdarrenr	printf("search(%#x) = %d (0)\n", ip.in4.s_addr,
207255332Scy		ipf_pool_search(ipo, 4, &ip, 1));
208145516Sdarrenr
209145516Sdarrenr	ip.in4.s_addr = 0x0a010001;
210145516Sdarrenr	printf("search(%#x) = %d (1)\n", ip.in4.s_addr,
211255332Scy		ipf_pool_search(ipo, 4, &ip, 1));
212145516Sdarrenr
213145516Sdarrenr	ip.in4.s_addr = 0x0a010101;
214145516Sdarrenr	printf("search(%#x) = %d (1)\n", ip.in4.s_addr,
215255332Scy		ipf_pool_search(ipo, 4, &ip, 1));
216145516Sdarrenr
217145516Sdarrenr	ip.in4.s_addr = 0x0a010201;
218145516Sdarrenr	printf("search(%#x) = %d (0)\n", ip.in4.s_addr,
219255332Scy		ipf_pool_search(ipo, 4, &ip, 1));
220145516Sdarrenr
221145516Sdarrenr	ip.in4.s_addr = 0x0a010203;
222145516Sdarrenr	printf("search(%#x) = %d (1)\n", ip.in4.s_addr,
223255332Scy		ipf_pool_search(ipo, 4, &ip, 1));
224145516Sdarrenr
225145516Sdarrenr	ip.in4.s_addr = 0x0a01020f;
226145516Sdarrenr	printf("search(%#x) = %d (1)\n", ip.in4.s_addr,
227255332Scy		ipf_pool_search(ipo, 4, &ip, 1));
228145516Sdarrenr
229145516Sdarrenr	ip.in4.s_addr = 0x0b00aabb;
230145516Sdarrenr	printf("search(%#x) = %d (-1)\n", ip.in4.s_addr,
231255332Scy		ipf_pool_search(ipo, 4, &ip, 1));
232145516Sdarrenr
233145516Sdarrenr#ifdef	DEBUG_POOL
234255332Scy	treeprint(ipo);
235145516Sdarrenr#endif
236145516Sdarrenr
237255332Scy	ipf_pool_fini();
238145516Sdarrenr
239145516Sdarrenr	return 0;
240145516Sdarrenr}
241145516Sdarrenr
242145516Sdarrenr
243145516Sdarrenrvoid
244145516Sdarrenrtreeprint(ipo)
245255332Scy	ip_pool_t *ipo;
246145516Sdarrenr{
247145516Sdarrenr	ip_pool_node_t *c;
248145516Sdarrenr
249145516Sdarrenr	for (c = ipo->ipo_list; c != NULL; c = c->ipn_next)
250145516Sdarrenr		printf("Node %p(%s) (%#x/%#x) = %d hits %lu\n",
251145516Sdarrenr			c, c->ipn_name, c->ipn_addr.adf_addr.in4.s_addr,
252145516Sdarrenr			c->ipn_mask.adf_addr.in4.s_addr,
253145516Sdarrenr			c->ipn_info, c->ipn_hits);
254145516Sdarrenr}
255145516Sdarrenr#endif /* TEST_POOL */
256145516Sdarrenr
257145516Sdarrenr
258145516Sdarrenr/* ------------------------------------------------------------------------ */
259255332Scy/* Function:    ipf_pool_soft_create                                        */
260255332Scy/* Returns:     void *   - NULL = failure, else pointer to local context    */
261255332Scy/* Parameters:  softc(I) - pointer to soft context main structure           */
262255332Scy/*                                                                          */
263255332Scy/* Initialise the routing table data structures where required.             */
264255332Scy/* ------------------------------------------------------------------------ */
265255332Scystatic void *
266255332Scyipf_pool_soft_create(softc)
267255332Scy	ipf_main_softc_t *softc;
268255332Scy{
269255332Scy	ipf_pool_softc_t *softp;
270255332Scy
271255332Scy	KMALLOC(softp, ipf_pool_softc_t *);
272255332Scy	if (softp == NULL) {
273255332Scy		IPFERROR(70032);
274255332Scy		return NULL;
275255332Scy	}
276255332Scy
277255332Scy	bzero((char *)softp, sizeof(*softp));
278255332Scy
279255332Scy	softp->ipf_radix = ipf_rx_create();
280255332Scy	if (softp->ipf_radix == NULL) {
281255332Scy		IPFERROR(70033);
282255332Scy		KFREE(softp);
283255332Scy		return NULL;
284255332Scy	}
285255332Scy
286255332Scy	return softp;
287255332Scy}
288255332Scy
289255332Scy
290255332Scy/* ------------------------------------------------------------------------ */
291255332Scy/* Function:    ipf_pool_soft_init                                          */
292145516Sdarrenr/* Returns:     int     - 0 = success, else error                           */
293255332Scy/* Parameters:  softc(I) - pointer to soft context main structure           */
294255332Scy/*              arg(I)   - pointer to local context to use                  */
295145516Sdarrenr/*                                                                          */
296145516Sdarrenr/* Initialise the routing table data structures where required.             */
297145516Sdarrenr/* ------------------------------------------------------------------------ */
298255332Scystatic int
299255332Scyipf_pool_soft_init(softc, arg)
300255332Scy	ipf_main_softc_t *softc;
301255332Scy	void *arg;
302145516Sdarrenr{
303255332Scy	ipf_pool_softc_t *softp = arg;
304145516Sdarrenr
305255332Scy	ipf_rx_init(softp->ipf_radix);
306145516Sdarrenr
307145516Sdarrenr	return 0;
308145516Sdarrenr}
309145516Sdarrenr
310145516Sdarrenr
311145516Sdarrenr/* ------------------------------------------------------------------------ */
312255332Scy/* Function:    ipf_pool_soft_fini                                          */
313255332Scy/* Returns:     Nil                                                         */
314255332Scy/* Parameters:  softc(I) - pointer to soft context main structure           */
315255332Scy/*              arg(I)   - pointer to local context to use                  */
316145516Sdarrenr/* Locks:       WRITE(ipf_global)                                           */
317145516Sdarrenr/*                                                                          */
318145516Sdarrenr/* Clean up all the pool data structures allocated and call the cleanup     */
319255332Scy/* function for the radix tree that supports the pools. ipf_pool_destroy is */
320145516Sdarrenr/* used to delete the pools one by one to ensure they're properly freed up. */
321145516Sdarrenr/* ------------------------------------------------------------------------ */
322255332Scystatic void
323255332Scyipf_pool_soft_fini(softc, arg)
324255332Scy	ipf_main_softc_t *softc;
325255332Scy	void *arg;
326145516Sdarrenr{
327255332Scy	ipf_pool_softc_t *softp = arg;
328145516Sdarrenr	ip_pool_t *p, *q;
329145516Sdarrenr	int i;
330145516Sdarrenr
331255332Scy	softc = arg;
332255332Scy
333255332Scy	for (i = -1; i <= IPL_LOGMAX; i++) {
334255332Scy		for (q = softp->ipf_pool_list[i + 1]; (p = q) != NULL; ) {
335145516Sdarrenr			q = p->ipo_next;
336255332Scy			(void) ipf_pool_destroy(softc, arg, i, p->ipo_name);
337145516Sdarrenr		}
338145516Sdarrenr	}
339255332Scy}
340145516Sdarrenr
341255332Scy
342255332Scy/* ------------------------------------------------------------------------ */
343255332Scy/* Function:    ipf_pool_soft_destroy                                       */
344255332Scy/* Returns:     Nil                                                         */
345255332Scy/* Parameters:  softc(I) - pointer to soft context main structure           */
346255332Scy/*              arg(I)   - pointer to local context to use                  */
347255332Scy/*                                                                          */
348255332Scy/* Clean up the pool by free'ing the radix tree associated with it and free */
349255332Scy/* up the pool context too.                                                 */
350255332Scy/* ------------------------------------------------------------------------ */
351255332Scystatic void
352255332Scyipf_pool_soft_destroy(softc, arg)
353255332Scy	ipf_main_softc_t *softc;
354255332Scy	void *arg;
355255332Scy{
356255332Scy	ipf_pool_softc_t *softp = arg;
357255332Scy
358255332Scy	ipf_rx_destroy(softp->ipf_radix);
359255332Scy
360255332Scy	KFREE(softp);
361255332Scy}
362255332Scy
363255332Scy
364255332Scy/* ------------------------------------------------------------------------ */
365255332Scy/* Function:   ipf_pool_node_add                                            */
366255332Scy/* Returns:    int - 0 = success, else error                                */
367255332Scy/* Parameters: softc(I) - pointer to soft context main structure            */
368255332Scy/*             arg(I)   - pointer to local context to use                   */
369255332Scy/*             op(I) - pointer to lookup operatin data                      */
370255332Scy/*                                                                          */
371255332Scy/* When adding a new node, a check is made to ensure that the address/mask  */
372255332Scy/* pair supplied has been appropriately prepared by applying the mask to    */
373255332Scy/* the address prior to calling for the pair to be added.                   */
374255332Scy/* ------------------------------------------------------------------------ */
375255332Scystatic int
376255332Scyipf_pool_node_add(softc, arg, op, uid)
377255332Scy	ipf_main_softc_t *softc;
378255332Scy	void *arg;
379255332Scy	iplookupop_t *op;
380255332Scy	int uid;
381255332Scy{
382255332Scy	ip_pool_node_t node, *m;
383255332Scy	ip_pool_t *p;
384255332Scy	int err;
385255332Scy
386255332Scy	if (op->iplo_size != sizeof(node)) {
387255332Scy		IPFERROR(70014);
388255332Scy		return EINVAL;
389255332Scy	}
390255332Scy
391255332Scy	err = COPYIN(op->iplo_struct, &node, sizeof(node));
392255332Scy	if (err != 0) {
393255332Scy		IPFERROR(70015);
394255332Scy		return EFAULT;
395255332Scy	}
396255332Scy
397255332Scy	p = ipf_pool_find(arg, op->iplo_unit, op->iplo_name);
398255332Scy	if (p == NULL) {
399255332Scy		IPFERROR(70017);
400255332Scy		return ESRCH;
401255332Scy	}
402255332Scy
403255332Scy	if (node.ipn_addr.adf_family == AF_INET) {
404255332Scy		if (node.ipn_addr.adf_len != offsetof(addrfamily_t, adf_addr) +
405255332Scy					     sizeof(struct in_addr)) {
406255332Scy			IPFERROR(70028);
407255332Scy			return EINVAL;
408255332Scy		}
409255332Scy	}
410255332Scy#ifdef USE_INET6
411255332Scy	else if (node.ipn_addr.adf_family == AF_INET6) {
412255332Scy		if (node.ipn_addr.adf_len != offsetof(addrfamily_t, adf_addr) +
413255332Scy					     sizeof(struct in6_addr)) {
414255332Scy			IPFERROR(70034);
415255332Scy			return EINVAL;
416255332Scy		}
417255332Scy	}
418145516Sdarrenr#endif
419255332Scy	if (node.ipn_mask.adf_len != node.ipn_addr.adf_len) {
420255332Scy		IPFERROR(70029);
421255332Scy		return EINVAL;
422255332Scy	}
423255332Scy
424255332Scy	/*
425255332Scy	 * Check that the address/mask pair works.
426255332Scy	 */
427255332Scy	if (node.ipn_addr.adf_family == AF_INET) {
428255332Scy		if ((node.ipn_addr.adf_addr.in4.s_addr &
429255332Scy		     node.ipn_mask.adf_addr.in4.s_addr) !=
430255332Scy		    node.ipn_addr.adf_addr.in4.s_addr) {
431255332Scy			IPFERROR(70035);
432255332Scy			return EINVAL;
433255332Scy		}
434255332Scy	}
435255332Scy#ifdef USE_INET6
436255332Scy	else if (node.ipn_addr.adf_family == AF_INET6) {
437255332Scy		if (IP6_MASKNEQ(&node.ipn_addr.adf_addr.in6,
438255332Scy				&node.ipn_mask.adf_addr.in6,
439255332Scy				&node.ipn_addr.adf_addr.in6)) {
440255332Scy			IPFERROR(70036);
441255332Scy			return EINVAL;
442255332Scy		}
443255332Scy	}
444255332Scy#endif
445255332Scy
446255332Scy	/*
447255332Scy	 * add an entry to a pool - return an error if it already
448255332Scy	 * exists remove an entry from a pool - if it exists
449255332Scy	 * - in both cases, the pool *must* exist!
450255332Scy	 */
451255332Scy	m = ipf_pool_findeq(arg, p, &node.ipn_addr, &node.ipn_mask);
452255332Scy	if (m != NULL) {
453255332Scy		IPFERROR(70018);
454255332Scy		return EEXIST;
455255332Scy	}
456255332Scy	err = ipf_pool_insert_node(softc, arg, p, &node);
457255332Scy
458255332Scy	return err;
459145516Sdarrenr}
460145516Sdarrenr
461145516Sdarrenr
462145516Sdarrenr/* ------------------------------------------------------------------------ */
463255332Scy/* Function:   ipf_pool_node_del                                            */
464255332Scy/* Returns:    int - 0 = success, else error                                */
465255332Scy/* Parameters: softc(I) - pointer to soft context main structure            */
466255332Scy/*             arg(I)   - pointer to local context to use                   */
467255332Scy/*             op(I)    - pointer to lookup operatin data                   */
468145516Sdarrenr/*                                                                          */
469255332Scy/* ------------------------------------------------------------------------ */
470255332Scystatic int
471255332Scyipf_pool_node_del(softc, arg, op, uid)
472255332Scy	ipf_main_softc_t *softc;
473255332Scy	void *arg;
474255332Scy	iplookupop_t *op;
475255332Scy	int uid;
476255332Scy{
477255332Scy	ip_pool_node_t node, *m;
478255332Scy	ip_pool_t *p;
479255332Scy	int err;
480255332Scy
481255332Scy
482255332Scy	if (op->iplo_size != sizeof(node)) {
483255332Scy		IPFERROR(70019);
484255332Scy		return EINVAL;
485255332Scy	}
486255332Scy	node.ipn_uid = uid;
487255332Scy
488255332Scy	err = COPYIN(op->iplo_struct, &node, sizeof(node));
489255332Scy	if (err != 0) {
490255332Scy		IPFERROR(70020);
491255332Scy		return EFAULT;
492255332Scy	}
493255332Scy
494255332Scy	if (node.ipn_addr.adf_family == AF_INET) {
495255332Scy		if (node.ipn_addr.adf_len != offsetof(addrfamily_t, adf_addr) +
496255332Scy					     sizeof(struct in_addr)) {
497255332Scy			IPFERROR(70030);
498255332Scy			return EINVAL;
499255332Scy		}
500255332Scy	}
501255332Scy#ifdef USE_INET6
502255332Scy	else if (node.ipn_addr.adf_family == AF_INET6) {
503255332Scy		if (node.ipn_addr.adf_len != offsetof(addrfamily_t, adf_addr) +
504255332Scy					     sizeof(struct in6_addr)) {
505255332Scy			IPFERROR(70037);
506255332Scy			return EINVAL;
507255332Scy		}
508255332Scy	}
509255332Scy#endif
510255332Scy	if (node.ipn_mask.adf_len != node.ipn_addr.adf_len) {
511255332Scy		IPFERROR(70031);
512255332Scy		return EINVAL;
513255332Scy	}
514255332Scy
515255332Scy	p = ipf_pool_find(arg, op->iplo_unit, op->iplo_name);
516255332Scy	if (p == NULL) {
517255332Scy		IPFERROR(70021);
518255332Scy		return ESRCH;
519255332Scy	}
520255332Scy
521255332Scy	m = ipf_pool_findeq(arg, p, &node.ipn_addr, &node.ipn_mask);
522255332Scy	if (m == NULL) {
523255332Scy		IPFERROR(70022);
524255332Scy		return ENOENT;
525255332Scy	}
526255332Scy
527255332Scy	if ((uid != 0) && (uid != m->ipn_uid)) {
528255332Scy		IPFERROR(70024);
529255332Scy		return EACCES;
530255332Scy	}
531255332Scy
532255332Scy	err = ipf_pool_remove_node(softc, arg, p, m);
533255332Scy
534255332Scy	return err;
535255332Scy}
536255332Scy
537255332Scy
538255332Scy/* ------------------------------------------------------------------------ */
539255332Scy/* Function:   ipf_pool_table_add                                           */
540255332Scy/* Returns:    int - 0 = success, else error                                */
541255332Scy/* Parameters: softc(I) - pointer to soft context main structure            */
542255332Scy/*             arg(I)   - pointer to local context to use                   */
543255332Scy/*             op(I)    - pointer to lookup operatin data                   */
544255332Scy/*                                                                          */
545255332Scy/* ------------------------------------------------------------------------ */
546255332Scystatic int
547255332Scyipf_pool_table_add(softc, arg, op)
548255332Scy	ipf_main_softc_t *softc;
549255332Scy	void *arg;
550255332Scy	iplookupop_t *op;
551255332Scy{
552255332Scy	int err;
553255332Scy
554255332Scy	if (((op->iplo_arg & LOOKUP_ANON) == 0) &&
555255332Scy	    (ipf_pool_find(arg, op->iplo_unit, op->iplo_name) != NULL)) {
556255332Scy		IPFERROR(70023);
557255332Scy		err = EEXIST;
558255332Scy	} else {
559255332Scy		err = ipf_pool_create(softc, arg, op);
560255332Scy	}
561255332Scy
562255332Scy	return err;
563255332Scy}
564255332Scy
565255332Scy
566255332Scy/* ------------------------------------------------------------------------ */
567255332Scy/* Function:   ipf_pool_table_del                                           */
568255332Scy/* Returns:    int - 0 = success, else error                                */
569255332Scy/* Parameters: softc(I) - pointer to soft context main structure            */
570255332Scy/*             arg(I)   - pointer to local context to use                   */
571255332Scy/*             op(I)    - pointer to lookup operatin data                   */
572255332Scy/*                                                                          */
573255332Scy/* ------------------------------------------------------------------------ */
574255332Scystatic int
575255332Scyipf_pool_table_del(softc, arg, op)
576255332Scy	ipf_main_softc_t *softc;
577255332Scy	void *arg;
578255332Scy	iplookupop_t *op;
579255332Scy{
580255332Scy	return ipf_pool_destroy(softc, arg, op->iplo_unit, op->iplo_name);
581255332Scy}
582255332Scy
583255332Scy
584255332Scy/* ------------------------------------------------------------------------ */
585255332Scy/* Function:    ipf_pool_statistics                                         */
586255332Scy/* Returns:     int      - 0 = success, else error                          */
587255332Scy/* Parameters:  softc(I) - pointer to soft context main structure           */
588255332Scy/*              arg(I)   - pointer to local context to use                  */
589255332Scy/*              op(I)    - pointer to lookup operatin data                  */
590255332Scy/*                                                                          */
591145516Sdarrenr/* Copy the current statistics out into user space, collecting pool list    */
592145516Sdarrenr/* pointers as appropriate for later use.                                   */
593145516Sdarrenr/* ------------------------------------------------------------------------ */
594255332Scystatic int
595255332Scyipf_pool_stats_get(softc, arg, op)
596255332Scy	ipf_main_softc_t *softc;
597255332Scy	void *arg;
598255332Scy	iplookupop_t *op;
599145516Sdarrenr{
600255332Scy	ipf_pool_softc_t *softp = arg;
601255332Scy	ipf_pool_stat_t stats;
602145516Sdarrenr	int unit, i, err = 0;
603145516Sdarrenr
604255332Scy	if (op->iplo_size != sizeof(ipf_pool_stat_t)) {
605255332Scy		IPFERROR(70001);
606145516Sdarrenr		return EINVAL;
607255332Scy	}
608145516Sdarrenr
609255332Scy	bcopy((char *)&softp->ipf_pool_stats, (char *)&stats, sizeof(stats));
610145516Sdarrenr	unit = op->iplo_unit;
611145516Sdarrenr	if (unit == IPL_LOGALL) {
612255332Scy		for (i = 0; i <= LOOKUP_POOL_MAX; i++)
613255332Scy			stats.ipls_list[i] = softp->ipf_pool_list[i];
614255332Scy	} else if (unit >= 0 && unit <= IPL_LOGMAX) {
615255332Scy		unit++;						/* -1 => 0 */
616145516Sdarrenr		if (op->iplo_name[0] != '\0')
617255332Scy			stats.ipls_list[unit] = ipf_pool_exists(softp, unit - 1,
618255332Scy								op->iplo_name);
619145516Sdarrenr		else
620255332Scy			stats.ipls_list[unit] = softp->ipf_pool_list[unit];
621255332Scy	} else {
622255332Scy		IPFERROR(70025);
623145516Sdarrenr		err = EINVAL;
624255332Scy	}
625255332Scy	if (err == 0) {
626145516Sdarrenr		err = COPYOUT(&stats, op->iplo_struct, sizeof(stats));
627255332Scy		if (err != 0) {
628255332Scy			IPFERROR(70026);
629255332Scy			return EFAULT;
630255332Scy		}
631255332Scy	}
632255332Scy	return 0;
633145516Sdarrenr}
634145516Sdarrenr
635145516Sdarrenr
636145516Sdarrenr/* ------------------------------------------------------------------------ */
637255332Scy/* Function:    ipf_pool_exists                                             */
638255332Scy/* Returns:     int      - 0 = success, else error                          */
639255332Scy/* Parameters:  softp(I) - pointer to soft context pool information         */
640255332Scy/*              unit(I)  - ipfilter device to which we are working on       */
641255332Scy/*              name(I)  - name of the pool                                 */
642145516Sdarrenr/*                                                                          */
643145516Sdarrenr/* Find a matching pool inside the collection of pools for a particular     */
644145516Sdarrenr/* device, indicated by the unit number.                                    */
645145516Sdarrenr/* ------------------------------------------------------------------------ */
646255332Scystatic void *
647255332Scyipf_pool_exists(softp, unit, name)
648255332Scy	ipf_pool_softc_t *softp;
649255332Scy	int unit;
650255332Scy	char *name;
651145516Sdarrenr{
652145516Sdarrenr	ip_pool_t *p;
653255332Scy	int i;
654145516Sdarrenr
655255332Scy	if (unit == IPL_LOGALL) {
656255332Scy		for (i = 0; i <= LOOKUP_POOL_MAX; i++) {
657255332Scy			for (p = softp->ipf_pool_list[i]; p != NULL;
658255332Scy			     p = p->ipo_next) {
659255332Scy				if (strncmp(p->ipo_name, name,
660255332Scy					    sizeof(p->ipo_name)) == 0)
661255332Scy					break;
662255332Scy			}
663255332Scy			if (p != NULL)
664255332Scy				break;
665255332Scy		}
666255332Scy	} else {
667255332Scy		for (p = softp->ipf_pool_list[unit + 1]; p != NULL;
668255332Scy		     p = p->ipo_next)
669255332Scy			if (strncmp(p->ipo_name, name,
670255332Scy				    sizeof(p->ipo_name)) == 0)
671255332Scy				break;
672255332Scy	}
673145516Sdarrenr	return p;
674145516Sdarrenr}
675145516Sdarrenr
676145516Sdarrenr
677145516Sdarrenr/* ------------------------------------------------------------------------ */
678255332Scy/* Function:    ipf_pool_find                                               */
679255332Scy/* Returns:     int    - 0 = success, else error                            */
680255332Scy/* Parameters:  arg(I)  - pointer to local context to use                   */
681255332Scy/*              unit(I) - ipfilter device to which we are working on        */
682255332Scy/*              name(I)  - name of the pool                                 */
683170263Sdarrenr/*                                                                          */
684170263Sdarrenr/* Find a matching pool inside the collection of pools for a particular     */
685170263Sdarrenr/* device, indicated by the unit number.  If it is marked for deletion then */
686170263Sdarrenr/* pretend it does not exist.                                               */
687170263Sdarrenr/* ------------------------------------------------------------------------ */
688255332Scystatic void *
689255332Scyipf_pool_find(arg, unit, name)
690255332Scy	void *arg;
691255332Scy	int unit;
692255332Scy	char *name;
693170263Sdarrenr{
694255332Scy	ipf_pool_softc_t *softp = arg;
695170263Sdarrenr	ip_pool_t *p;
696170263Sdarrenr
697255332Scy	p = ipf_pool_exists(softp, unit, name);
698170263Sdarrenr	if ((p != NULL) && (p->ipo_flags & IPOOL_DELETE))
699170263Sdarrenr		return NULL;
700170263Sdarrenr
701170263Sdarrenr	return p;
702170263Sdarrenr}
703170263Sdarrenr
704170263Sdarrenr
705170263Sdarrenr/* ------------------------------------------------------------------------ */
706255332Scy/* Function:    ipf_pool_select_add_ref                                     */
707255332Scy/* Returns:     int - 0 = success, else error                               */
708255332Scy/* Parameters:  arg(I)  - pointer to local context to use                   */
709255332Scy/*              unit(I) - ipfilter device to which we are working on        */
710255332Scy/*              name(I)  - name of the pool                                 */
711255332Scy/*                                                                          */
712255332Scy/* ------------------------------------------------------------------------ */
713255332Scystatic void *
714255332Scyipf_pool_select_add_ref(arg, unit, name)
715255332Scy	void *arg;
716255332Scy	int unit;
717255332Scy	char *name;
718255332Scy{
719255332Scy	ip_pool_t *p;
720255332Scy
721255332Scy	p = ipf_pool_find(arg, -1, name);
722255332Scy	if (p == NULL)
723255332Scy		p = ipf_pool_find(arg, unit, name);
724255332Scy	if (p != NULL) {
725255332Scy		ATOMIC_INC32(p->ipo_ref);
726255332Scy	}
727255332Scy	return p;
728255332Scy}
729255332Scy
730255332Scy
731255332Scy/* ------------------------------------------------------------------------ */
732255332Scy/* Function:    ipf_pool_findeq                                             */
733145516Sdarrenr/* Returns:     int     - 0 = success, else error                           */
734255332Scy/* Parameters:  softp(I) - pointer to soft context pool information         */
735255332Scy/*              ipo(I)  - pointer to the pool getting the new node.         */
736255332Scy/*              addr(I) - pointer to address information to match on        */
737255332Scy/*              mask(I) - pointer to the address mask to match              */
738145516Sdarrenr/*                                                                          */
739145516Sdarrenr/* Searches for an exact match of an entry in the pool.                     */
740145516Sdarrenr/* ------------------------------------------------------------------------ */
741255332Scyextern void printhostmask __P((int, u_32_t *, u_32_t *));
742255332Scystatic ip_pool_node_t *
743255332Scyipf_pool_findeq(softp, ipo, addr, mask)
744255332Scy	ipf_pool_softc_t *softp;
745255332Scy	ip_pool_t *ipo;
746255332Scy	addrfamily_t *addr, *mask;
747145516Sdarrenr{
748255332Scy	ipf_rdx_node_t *n;
749145516Sdarrenr
750255332Scy	n = ipo->ipo_head->lookup(ipo->ipo_head, addr, mask);
751145516Sdarrenr	return (ip_pool_node_t *)n;
752145516Sdarrenr}
753145516Sdarrenr
754145516Sdarrenr
755145516Sdarrenr/* ------------------------------------------------------------------------ */
756255332Scy/* Function:    ipf_pool_search                                             */
757145516Sdarrenr/* Returns:     int     - 0 == +ve match, -1 == error, 1 == -ve/no match    */
758255332Scy/* Parameters:  softc(I) - pointer to soft context main structure           */
759255332Scy/*              tptr(I)    - pointer to the pool to search                  */
760145516Sdarrenr/*              version(I) - IP protocol version (4 or 6)                   */
761145516Sdarrenr/*              dptr(I)    - pointer to address information                 */
762255332Scy/*              bytes(I)   - length of packet                               */
763145516Sdarrenr/*                                                                          */
764145516Sdarrenr/* Search the pool for a given address and return a search result.          */
765145516Sdarrenr/* ------------------------------------------------------------------------ */
766255332Scystatic int
767255332Scyipf_pool_search(softc, tptr, ipversion, dptr, bytes)
768255332Scy	ipf_main_softc_t *softc;
769255332Scy	void *tptr;
770255332Scy	int ipversion;
771255332Scy	void *dptr;
772255332Scy	u_int bytes;
773145516Sdarrenr{
774255332Scy	ipf_rdx_node_t *rn;
775145516Sdarrenr	ip_pool_node_t *m;
776145516Sdarrenr	i6addr_t *addr;
777145516Sdarrenr	addrfamily_t v;
778145516Sdarrenr	ip_pool_t *ipo;
779145516Sdarrenr	int rv;
780145516Sdarrenr
781145516Sdarrenr	ipo = tptr;
782145516Sdarrenr	if (ipo == NULL)
783145516Sdarrenr		return -1;
784145516Sdarrenr
785145516Sdarrenr	rv = 1;
786145516Sdarrenr	m = NULL;
787145516Sdarrenr	addr = (i6addr_t *)dptr;
788145516Sdarrenr	bzero(&v, sizeof(v));
789145516Sdarrenr
790170263Sdarrenr	if (ipversion == 4) {
791255332Scy		v.adf_family = AF_INET;
792255332Scy		v.adf_len = offsetof(addrfamily_t, adf_addr) +
793255332Scy			    sizeof(struct in_addr);
794145516Sdarrenr		v.adf_addr.in4 = addr->in4;
795145516Sdarrenr#ifdef USE_INET6
796170263Sdarrenr	} else if (ipversion == 6) {
797255332Scy		v.adf_family = AF_INET6;
798255332Scy		v.adf_len = offsetof(addrfamily_t, adf_addr) +
799255332Scy			    sizeof(struct in6_addr);
800145516Sdarrenr		v.adf_addr.in6 = addr->in6;
801145516Sdarrenr#endif
802145516Sdarrenr	} else
803145516Sdarrenr		return -1;
804145516Sdarrenr
805255332Scy	READ_ENTER(&softc->ipf_poolrw);
806145516Sdarrenr
807255332Scy	rn = ipo->ipo_head->matchaddr(ipo->ipo_head, &v);
808145516Sdarrenr
809255332Scy	if ((rn != NULL) && (rn->root == 0)) {
810145516Sdarrenr		m = (ip_pool_node_t *)rn;
811145516Sdarrenr		ipo->ipo_hits++;
812255332Scy		m->ipn_bytes += bytes;
813145516Sdarrenr		m->ipn_hits++;
814145516Sdarrenr		rv = m->ipn_info;
815145516Sdarrenr	}
816255332Scy	RWLOCK_EXIT(&softc->ipf_poolrw);
817145516Sdarrenr	return rv;
818145516Sdarrenr}
819145516Sdarrenr
820145516Sdarrenr
821145516Sdarrenr/* ------------------------------------------------------------------------ */
822255332Scy/* Function:    ipf_pool_insert_node                                        */
823255332Scy/* Returns:     int      - 0 = success, else error                          */
824255332Scy/* Parameters:  softc(I) - pointer to soft context main structure           */
825255332Scy/*              softp(I) - pointer to soft context pool information         */
826255332Scy/*              ipo(I)   - pointer to the pool getting the new node.        */
827255332Scy/*              node(I)  - structure with address/mask to add               */
828255332Scy/* Locks:       WRITE(ipf_poolrw)                                           */
829145516Sdarrenr/*                                                                          */
830145516Sdarrenr/* Add another node to the pool given by ipo.  The three parameters passed  */
831145516Sdarrenr/* in (addr, mask, info) shold all be stored in the node.                   */
832145516Sdarrenr/* ------------------------------------------------------------------------ */
833255332Scystatic int
834255332Scyipf_pool_insert_node(softc, softp, ipo, node)
835255332Scy	ipf_main_softc_t *softc;
836255332Scy	ipf_pool_softc_t *softp;
837255332Scy	ip_pool_t *ipo;
838255332Scy	struct ip_pool_node *node;
839145516Sdarrenr{
840255332Scy	ipf_rdx_node_t *rn;
841145516Sdarrenr	ip_pool_node_t *x;
842145516Sdarrenr
843255332Scy	if ((node->ipn_addr.adf_len > sizeof(*rn)) ||
844255332Scy	    (node->ipn_addr.adf_len < 4)) {
845255332Scy		IPFERROR(70003);
846255332Scy		return EINVAL;
847255332Scy	}
848255332Scy
849255332Scy	if ((node->ipn_mask.adf_len > sizeof(*rn)) ||
850255332Scy	    (node->ipn_mask.adf_len < 4)) {
851255332Scy		IPFERROR(70004);
852255332Scy		return EINVAL;
853255332Scy	}
854255332Scy
855145516Sdarrenr	KMALLOC(x, ip_pool_node_t *);
856145516Sdarrenr	if (x == NULL) {
857255332Scy		IPFERROR(70002);
858145516Sdarrenr		return ENOMEM;
859145516Sdarrenr	}
860145516Sdarrenr
861255332Scy	*x = *node;
862255332Scy	bzero((char *)x->ipn_nodes, sizeof(x->ipn_nodes));
863255332Scy	x->ipn_owner = ipo;
864255332Scy	x->ipn_hits = 0;
865255332Scy	x->ipn_next = NULL;
866255332Scy	x->ipn_pnext = NULL;
867255332Scy	x->ipn_dnext = NULL;
868255332Scy	x->ipn_pdnext = NULL;
869145516Sdarrenr
870255332Scy	if (x->ipn_die != 0) {
871255332Scy		/*
872255332Scy		 * If the new node has a given expiration time, insert it
873255332Scy		 * into the list of expiring nodes with the ones to be
874255332Scy		 * removed first added to the front of the list. The
875255332Scy		 * insertion is O(n) but it is kept sorted for quick scans
876255332Scy		 * at expiration interval checks.
877255332Scy		 */
878255332Scy		ip_pool_node_t *n;
879145516Sdarrenr
880255332Scy		x->ipn_die = softc->ipf_ticks + IPF_TTLVAL(x->ipn_die);
881255332Scy		for (n = softp->ipf_node_explist; n != NULL; n = n->ipn_dnext) {
882255332Scy			if (x->ipn_die < n->ipn_die)
883255332Scy				break;
884255332Scy			if (n->ipn_dnext == NULL) {
885255332Scy				/*
886255332Scy				 * We've got to the last node and everything
887255332Scy				 * wanted to be expired before this new node,
888255332Scy				 * so we have to tack it on the end...
889255332Scy				 */
890255332Scy				n->ipn_dnext = x;
891255332Scy				x->ipn_pdnext = &n->ipn_dnext;
892255332Scy				n = NULL;
893255332Scy				break;
894255332Scy			}
895255332Scy		}
896145516Sdarrenr
897255332Scy		if (softp->ipf_node_explist == NULL) {
898255332Scy			softp->ipf_node_explist = x;
899255332Scy			x->ipn_pdnext = &softp->ipf_node_explist;
900255332Scy		} else if (n != NULL) {
901255332Scy			x->ipn_dnext = n;
902255332Scy			x->ipn_pdnext = n->ipn_pdnext;
903255332Scy			n->ipn_pdnext = &x->ipn_dnext;
904255332Scy		}
905255332Scy	}
906255332Scy
907255332Scy	rn = ipo->ipo_head->addaddr(ipo->ipo_head, &x->ipn_addr, &x->ipn_mask,
908255332Scy				    x->ipn_nodes);
909145516Sdarrenr#ifdef	DEBUG_POOL
910145516Sdarrenr	printf("Added %p at %p\n", x, rn);
911145516Sdarrenr#endif
912145516Sdarrenr
913145516Sdarrenr	if (rn == NULL) {
914145516Sdarrenr		KFREE(x);
915255332Scy		IPFERROR(70005);
916145516Sdarrenr		return ENOMEM;
917145516Sdarrenr	}
918145516Sdarrenr
919170263Sdarrenr	x->ipn_ref = 1;
920255332Scy	x->ipn_pnext = ipo->ipo_tail;
921255332Scy	*ipo->ipo_tail = x;
922255332Scy	ipo->ipo_tail = &x->ipn_next;
923145516Sdarrenr
924255332Scy	softp->ipf_pool_stats.ipls_nodes++;
925145516Sdarrenr
926145516Sdarrenr	return 0;
927145516Sdarrenr}
928145516Sdarrenr
929145516Sdarrenr
930145516Sdarrenr/* ------------------------------------------------------------------------ */
931255332Scy/* Function:    ipf_pool_create                                             */
932255332Scy/* Returns:     int      - 0 = success, else error                          */
933255332Scy/* Parameters:  softc(I) - pointer to soft context main structure           */
934255332Scy/*              softp(I) - pointer to soft context pool information         */
935255332Scy/*              op(I)    - pointer to iplookup struct with call details     */
936255332Scy/* Locks:       WRITE(ipf_poolrw)                                           */
937145516Sdarrenr/*                                                                          */
938145516Sdarrenr/* Creates a new group according to the paramters passed in via the         */
939145516Sdarrenr/* iplookupop structure.  Does not check to see if the group already exists */
940145516Sdarrenr/* when being inserted - assume this has already been done.  If the pool is */
941145516Sdarrenr/* marked as being anonymous, give it a new, unique, identifier.  Call any  */
942145516Sdarrenr/* other functions required to initialise the structure.                    */
943170263Sdarrenr/*                                                                          */
944170263Sdarrenr/* If the structure is flagged for deletion then reset the flag and return, */
945170263Sdarrenr/* as this likely means we've tried to free a pool that is in use (flush)   */
946170263Sdarrenr/* and now want to repopulate it with "new" data.                           */
947145516Sdarrenr/* ------------------------------------------------------------------------ */
948255332Scystatic int
949255332Scyipf_pool_create(softc, softp, op)
950255332Scy	ipf_main_softc_t *softc;
951255332Scy	ipf_pool_softc_t *softp;
952255332Scy	iplookupop_t *op;
953145516Sdarrenr{
954145516Sdarrenr	char name[FR_GROUPLEN];
955145516Sdarrenr	int poolnum, unit;
956145516Sdarrenr	ip_pool_t *h;
957145516Sdarrenr
958170263Sdarrenr	unit = op->iplo_unit;
959145516Sdarrenr
960172771Sdarrenr	if ((op->iplo_arg & LOOKUP_ANON) == 0) {
961255332Scy		h = ipf_pool_exists(softp, unit, op->iplo_name);
962172771Sdarrenr		if (h != NULL) {
963255332Scy			if ((h->ipo_flags & IPOOL_DELETE) == 0) {
964255332Scy				IPFERROR(70006);
965172771Sdarrenr				return EEXIST;
966255332Scy			}
967170263Sdarrenr			h->ipo_flags &= ~IPOOL_DELETE;
968170263Sdarrenr			return 0;
969170263Sdarrenr		}
970172771Sdarrenr	}
971170263Sdarrenr
972172771Sdarrenr	KMALLOC(h, ip_pool_t *);
973255332Scy	if (h == NULL) {
974255332Scy		IPFERROR(70007);
975172771Sdarrenr		return ENOMEM;
976255332Scy	}
977172771Sdarrenr	bzero(h, sizeof(*h));
978172771Sdarrenr
979255332Scy	if (ipf_rx_inithead(softp->ipf_radix, &h->ipo_head) != 0) {
980172771Sdarrenr		KFREE(h);
981255332Scy		IPFERROR(70008);
982172771Sdarrenr		return ENOMEM;
983145516Sdarrenr	}
984145516Sdarrenr
985170263Sdarrenr	if ((op->iplo_arg & LOOKUP_ANON) != 0) {
986145516Sdarrenr		ip_pool_t *p;
987145516Sdarrenr
988170263Sdarrenr		h->ipo_flags |= IPOOL_ANON;
989170263Sdarrenr		poolnum = LOOKUP_ANON;
990145516Sdarrenr
991145516Sdarrenr#if defined(SNPRINTF) && defined(_KERNEL)
992145516Sdarrenr		SNPRINTF(name, sizeof(name), "%x", poolnum);
993145516Sdarrenr#else
994145516Sdarrenr		(void)sprintf(name, "%x", poolnum);
995145516Sdarrenr#endif
996145516Sdarrenr
997255332Scy		for (p = softp->ipf_pool_list[unit + 1]; p != NULL; ) {
998145516Sdarrenr			if (strncmp(name, p->ipo_name,
999145516Sdarrenr				    sizeof(p->ipo_name)) == 0) {
1000145516Sdarrenr				poolnum++;
1001145516Sdarrenr#if defined(SNPRINTF) && defined(_KERNEL)
1002145516Sdarrenr				SNPRINTF(name, sizeof(name), "%x", poolnum);
1003145516Sdarrenr#else
1004145516Sdarrenr				(void)sprintf(name, "%x", poolnum);
1005145516Sdarrenr#endif
1006255332Scy				p = softp->ipf_pool_list[unit + 1];
1007145516Sdarrenr			} else
1008145516Sdarrenr				p = p->ipo_next;
1009145516Sdarrenr		}
1010145516Sdarrenr
1011145516Sdarrenr		(void)strncpy(h->ipo_name, name, sizeof(h->ipo_name));
1012153872Sguido		(void)strncpy(op->iplo_name, name, sizeof(op->iplo_name));
1013145516Sdarrenr	} else {
1014170263Sdarrenr		(void)strncpy(h->ipo_name, op->iplo_name, sizeof(h->ipo_name));
1015145516Sdarrenr	}
1016145516Sdarrenr
1017255332Scy	h->ipo_radix = softp->ipf_radix;
1018172771Sdarrenr	h->ipo_ref = 1;
1019172771Sdarrenr	h->ipo_list = NULL;
1020255332Scy	h->ipo_tail = &h->ipo_list;
1021172771Sdarrenr	h->ipo_unit = unit;
1022255332Scy	h->ipo_next = softp->ipf_pool_list[unit + 1];
1023255332Scy	if (softp->ipf_pool_list[unit + 1] != NULL)
1024255332Scy		softp->ipf_pool_list[unit + 1]->ipo_pnext = &h->ipo_next;
1025255332Scy	h->ipo_pnext = &softp->ipf_pool_list[unit + 1];
1026255332Scy	softp->ipf_pool_list[unit + 1] = h;
1027145516Sdarrenr
1028255332Scy	softp->ipf_pool_stats.ipls_pools++;
1029145516Sdarrenr
1030145516Sdarrenr	return 0;
1031145516Sdarrenr}
1032145516Sdarrenr
1033145516Sdarrenr
1034145516Sdarrenr/* ------------------------------------------------------------------------ */
1035255332Scy/* Function:    ipf_pool_remove_node                                        */
1036255332Scy/* Returns:     int      - 0 = success, else error                          */
1037255332Scy/* Parameters:  softc(I) - pointer to soft context main structure           */
1038255332Scy/*              ipo(I)   - pointer to the pool to remove the node from.     */
1039255332Scy/*              ipe(I)   - address being deleted as a node                  */
1040255332Scy/* Locks:       WRITE(ipf_poolrw)                                           */
1041145516Sdarrenr/*                                                                          */
1042170263Sdarrenr/* Remove a node from the pool given by ipo.                                */
1043145516Sdarrenr/* ------------------------------------------------------------------------ */
1044255332Scystatic int
1045255332Scyipf_pool_remove_node(softc, softp, ipo, ipe)
1046255332Scy	ipf_main_softc_t *softc;
1047255332Scy	ipf_pool_softc_t *softp;
1048255332Scy	ip_pool_t *ipo;
1049255332Scy	ip_pool_node_t *ipe;
1050145516Sdarrenr{
1051255332Scy	void *ptr;
1052145516Sdarrenr
1053255332Scy	if (ipo->ipo_tail == &ipe->ipn_next)
1054255332Scy		ipo->ipo_tail = ipe->ipn_pnext;
1055255332Scy
1056170263Sdarrenr	if (ipe->ipn_pnext != NULL)
1057170263Sdarrenr		*ipe->ipn_pnext = ipe->ipn_next;
1058170263Sdarrenr	if (ipe->ipn_next != NULL)
1059170263Sdarrenr		ipe->ipn_next->ipn_pnext = ipe->ipn_pnext;
1060145516Sdarrenr
1061255332Scy	if (ipe->ipn_pdnext != NULL)
1062255332Scy		*ipe->ipn_pdnext = ipe->ipn_dnext;
1063255332Scy	if (ipe->ipn_dnext != NULL)
1064255332Scy		ipe->ipn_dnext->ipn_pdnext = ipe->ipn_pdnext;
1065145516Sdarrenr
1066255332Scy	ptr = ipo->ipo_head->deladdr(ipo->ipo_head, &ipe->ipn_addr,
1067255332Scy				     &ipe->ipn_mask);
1068145516Sdarrenr
1069255332Scy	if (ptr != NULL) {
1070255332Scy		ipf_pool_node_deref(softp, ipe);
1071255332Scy		return 0;
1072255332Scy	}
1073255332Scy	IPFERROR(70027);
1074255332Scy	return ESRCH;
1075145516Sdarrenr}
1076145516Sdarrenr
1077145516Sdarrenr
1078145516Sdarrenr/* ------------------------------------------------------------------------ */
1079255332Scy/* Function:    ipf_pool_destroy                                            */
1080145516Sdarrenr/* Returns:     int    - 0 = success, else error                            */
1081255332Scy/* Parameters:  softc(I) - pointer to soft context main structure           */
1082255332Scy/*              softp(I) - pointer to soft context pool information         */
1083255332Scy/*              unit(I)  - ipfilter device to which we are working on      */
1084255332Scy/*              name(I)  - name of the pool                                 */
1085255332Scy/* Locks:       WRITE(ipf_poolrw) or WRITE(ipf_global)                      */
1086145516Sdarrenr/*                                                                          */
1087145516Sdarrenr/* Search for a pool using paramters passed in and if it's not otherwise    */
1088170263Sdarrenr/* busy, free it.  If it is busy, clear all of its nodes, mark it for being */
1089170263Sdarrenr/* deleted and return an error saying it is busy.                           */
1090145516Sdarrenr/*                                                                          */
1091255332Scy/* NOTE: Because this function is called out of ipfdetach() where ipf_poolrw*/
1092145516Sdarrenr/* may not be initialised, we can't use an ASSERT to enforce the locking    */
1093255332Scy/* assertion that one of the two (ipf_poolrw,ipf_global) is held.           */
1094145516Sdarrenr/* ------------------------------------------------------------------------ */
1095255332Scystatic int
1096255332Scyipf_pool_destroy(softc, softp, unit, name)
1097255332Scy	ipf_main_softc_t *softc;
1098255332Scy	ipf_pool_softc_t *softp;
1099255332Scy	int unit;
1100255332Scy	char *name;
1101145516Sdarrenr{
1102145516Sdarrenr	ip_pool_t *ipo;
1103145516Sdarrenr
1104255332Scy	ipo = ipf_pool_exists(softp, unit, name);
1105255332Scy	if (ipo == NULL) {
1106255332Scy		IPFERROR(70009);
1107145516Sdarrenr		return ESRCH;
1108255332Scy	}
1109145516Sdarrenr
1110170263Sdarrenr	if (ipo->ipo_ref != 1) {
1111255332Scy		ipf_pool_clearnodes(softc, softp, ipo);
1112170263Sdarrenr		ipo->ipo_flags |= IPOOL_DELETE;
1113170263Sdarrenr		return 0;
1114170263Sdarrenr	}
1115145516Sdarrenr
1116255332Scy	ipf_pool_free(softc, softp, ipo);
1117145516Sdarrenr	return 0;
1118145516Sdarrenr}
1119145516Sdarrenr
1120145516Sdarrenr
1121145516Sdarrenr/* ------------------------------------------------------------------------ */
1122255332Scy/* Function:    ipf_pool_flush                                              */
1123145516Sdarrenr/* Returns:     int    - number of pools deleted                            */
1124255332Scy/* Parameters:  softc(I) - pointer to soft context main structure           */
1125255332Scy/*              arg(I)   - pointer to local context to use                  */
1126255332Scy/*              fp(I)    - which pool(s) to flush                           */
1127255332Scy/* Locks:       WRITE(ipf_poolrw) or WRITE(ipf_global)                      */
1128145516Sdarrenr/*                                                                          */
1129145516Sdarrenr/* Free all pools associated with the device that matches the unit number   */
1130145516Sdarrenr/* passed in with operation.                                                */
1131145516Sdarrenr/*                                                                          */
1132255332Scy/* NOTE: Because this function is called out of ipfdetach() where ipf_poolrw*/
1133145516Sdarrenr/* may not be initialised, we can't use an ASSERT to enforce the locking    */
1134255332Scy/* assertion that one of the two (ipf_poolrw,ipf_global) is held.           */
1135145516Sdarrenr/* ------------------------------------------------------------------------ */
1136255332Scystatic size_t
1137255332Scyipf_pool_flush(softc, arg, fp)
1138255332Scy	ipf_main_softc_t *softc;
1139255332Scy	void *arg;
1140255332Scy	iplookupflush_t *fp;
1141145516Sdarrenr{
1142255332Scy	ipf_pool_softc_t *softp = arg;
1143145516Sdarrenr	int i, num = 0, unit, err;
1144145516Sdarrenr	ip_pool_t *p, *q;
1145145516Sdarrenr
1146145516Sdarrenr	unit = fp->iplf_unit;
1147255332Scy	for (i = -1; i <= IPL_LOGMAX; i++) {
1148145516Sdarrenr		if (unit != IPLT_ALL && i != unit)
1149145516Sdarrenr			continue;
1150255332Scy		for (q = softp->ipf_pool_list[i + 1]; (p = q) != NULL; ) {
1151145516Sdarrenr			q = p->ipo_next;
1152255332Scy			err = ipf_pool_destroy(softc, softp, i, p->ipo_name);
1153145516Sdarrenr			if (err == 0)
1154145516Sdarrenr				num++;
1155145516Sdarrenr		}
1156145516Sdarrenr	}
1157145516Sdarrenr	return num;
1158145516Sdarrenr}
1159145516Sdarrenr
1160145516Sdarrenr
1161145516Sdarrenr/* ------------------------------------------------------------------------ */
1162255332Scy/* Function:    ipf_pool_free                                               */
1163145516Sdarrenr/* Returns:     void                                                        */
1164255332Scy/* Parameters:  softc(I) - pointer to soft context main structure           */
1165255332Scy/*              softp(I) - pointer to soft context pool information         */
1166255332Scy/*              ipo(I) - pointer to pool structure                          */
1167255332Scy/* Locks:       WRITE(ipf_poolrw) or WRITE(ipf_global)                      */
1168145516Sdarrenr/*                                                                          */
1169145516Sdarrenr/* Deletes the pool strucutre passed in from the list of pools and deletes  */
1170145516Sdarrenr/* all of the address information stored in it, including any tree data     */
1171145516Sdarrenr/* structures also allocated.                                               */
1172145516Sdarrenr/*                                                                          */
1173255332Scy/* NOTE: Because this function is called out of ipfdetach() where ipf_poolrw*/
1174145516Sdarrenr/* may not be initialised, we can't use an ASSERT to enforce the locking    */
1175255332Scy/* assertion that one of the two (ipf_poolrw,ipf_global) is held.           */
1176145516Sdarrenr/* ------------------------------------------------------------------------ */
1177255332Scystatic void
1178255332Scyipf_pool_free(softc, softp, ipo)
1179255332Scy	ipf_main_softc_t *softc;
1180255332Scy	ipf_pool_softc_t *softp;
1181255332Scy	ip_pool_t *ipo;
1182145516Sdarrenr{
1183170263Sdarrenr
1184255332Scy	ipf_pool_clearnodes(softc, softp, ipo);
1185170263Sdarrenr
1186170263Sdarrenr	if (ipo->ipo_next != NULL)
1187170263Sdarrenr		ipo->ipo_next->ipo_pnext = ipo->ipo_pnext;
1188170263Sdarrenr	*ipo->ipo_pnext = ipo->ipo_next;
1189255332Scy	ipf_rx_freehead(ipo->ipo_head);
1190170263Sdarrenr	KFREE(ipo);
1191170263Sdarrenr
1192255332Scy	softp->ipf_pool_stats.ipls_pools--;
1193170263Sdarrenr}
1194170263Sdarrenr
1195170263Sdarrenr
1196170263Sdarrenr/* ------------------------------------------------------------------------ */
1197255332Scy/* Function:    ipf_pool_clearnodes                                         */
1198170263Sdarrenr/* Returns:     void                                                        */
1199255332Scy/* Parameters:  softc(I) - pointer to soft context main structure           */
1200255332Scy/*              softp(I) - pointer to soft context pool information         */
1201255332Scy/*              ipo(I)   - pointer to pool structure                        */
1202255332Scy/* Locks:       WRITE(ipf_poolrw) or WRITE(ipf_global)                      */
1203170263Sdarrenr/*                                                                          */
1204170263Sdarrenr/* Deletes all nodes stored in a pool structure.                            */
1205170263Sdarrenr/* ------------------------------------------------------------------------ */
1206255332Scystatic void
1207255332Scyipf_pool_clearnodes(softc, softp, ipo)
1208255332Scy	ipf_main_softc_t *softc;
1209255332Scy	ipf_pool_softc_t *softp;
1210255332Scy	ip_pool_t *ipo;
1211170263Sdarrenr{
1212255332Scy	ip_pool_node_t *n, **next;
1213145516Sdarrenr
1214255332Scy	for (next = &ipo->ipo_list; (n = *next) != NULL; )
1215255332Scy		ipf_pool_remove_node(softc, softp, ipo, n);
1216145516Sdarrenr
1217145516Sdarrenr	ipo->ipo_list = NULL;
1218145516Sdarrenr}
1219145516Sdarrenr
1220145516Sdarrenr
1221145516Sdarrenr/* ------------------------------------------------------------------------ */
1222255332Scy/* Function:    ipf_pool_deref                                              */
1223145516Sdarrenr/* Returns:     void                                                        */
1224255332Scy/* Parameters:  softc(I) - pointer to soft context main structure           */
1225255332Scy/*              arg(I)   - pointer to local context to use                  */
1226255332Scy/*              pool(I)  - pointer to pool structure                        */
1227255332Scy/* Locks:       WRITE(ipf_poolrw)                                           */
1228145516Sdarrenr/*                                                                          */
1229145516Sdarrenr/* Drop the number of known references to this pool structure by one and if */
1230145516Sdarrenr/* we arrive at zero known references, free it.                             */
1231145516Sdarrenr/* ------------------------------------------------------------------------ */
1232255332Scystatic int
1233255332Scyipf_pool_deref(softc, arg, pool)
1234255332Scy	ipf_main_softc_t *softc;
1235255332Scy	void *arg, *pool;
1236145516Sdarrenr{
1237255332Scy	ip_pool_t *ipo = pool;
1238145516Sdarrenr
1239145516Sdarrenr	ipo->ipo_ref--;
1240170263Sdarrenr
1241145516Sdarrenr	if (ipo->ipo_ref == 0)
1242255332Scy		ipf_pool_free(softc, arg, ipo);
1243170263Sdarrenr
1244170263Sdarrenr	else if ((ipo->ipo_ref == 1) && (ipo->ipo_flags & IPOOL_DELETE))
1245255332Scy		ipf_pool_destroy(softc, arg, ipo->ipo_unit, ipo->ipo_name);
1246255332Scy
1247255332Scy	return 0;
1248145516Sdarrenr}
1249145516Sdarrenr
1250145516Sdarrenr
1251170263Sdarrenr/* ------------------------------------------------------------------------ */
1252255332Scy/* Function:    ipf_pool_node_deref                                         */
1253170263Sdarrenr/* Returns:     void                                                        */
1254255332Scy/* Parameters:  softp(I) - pointer to soft context pool information         */
1255255332Scy/*              ipn(I)   - pointer to pool structure                        */
1256255332Scy/* Locks:       WRITE(ipf_poolrw)                                           */
1257170263Sdarrenr/*                                                                          */
1258170263Sdarrenr/* Drop a reference to the pool node passed in and if we're the last, free  */
1259170263Sdarrenr/* it all up and adjust the stats accordingly.                              */
1260170263Sdarrenr/* ------------------------------------------------------------------------ */
1261255332Scystatic void
1262255332Scyipf_pool_node_deref(softp, ipn)
1263255332Scy	ipf_pool_softc_t *softp;
1264255332Scy	ip_pool_node_t *ipn;
1265170263Sdarrenr{
1266170263Sdarrenr
1267170263Sdarrenr	ipn->ipn_ref--;
1268170263Sdarrenr
1269170263Sdarrenr	if (ipn->ipn_ref == 0) {
1270170263Sdarrenr		KFREE(ipn);
1271255332Scy		softp->ipf_pool_stats.ipls_nodes--;
1272170263Sdarrenr	}
1273170263Sdarrenr}
1274170263Sdarrenr
1275170263Sdarrenr
1276170263Sdarrenr/* ------------------------------------------------------------------------ */
1277255332Scy/* Function:    ipf_pool_iter_next                                          */
1278170263Sdarrenr/* Returns:     void                                                        */
1279255332Scy/* Parameters:  softc(I) - pointer to soft context main structure           */
1280255332Scy/*              arg(I)   - pointer to local context to use                  */
1281255332Scy/*              token(I) - pointer to pool structure                        */
1282255332Scy/*              ilp(IO)  - pointer to pool iterating structure              */
1283170263Sdarrenr/*                                                                          */
1284170263Sdarrenr/* ------------------------------------------------------------------------ */
1285255332Scystatic int
1286255332Scyipf_pool_iter_next(softc, arg, token, ilp)
1287255332Scy	ipf_main_softc_t *softc;
1288255332Scy	void *arg;
1289255332Scy	ipftoken_t *token;
1290255332Scy	ipflookupiter_t *ilp;
1291170263Sdarrenr{
1292255332Scy	ipf_pool_softc_t *softp = arg;
1293170263Sdarrenr	ip_pool_node_t *node, zn, *nextnode;
1294170263Sdarrenr	ip_pool_t *ipo, zp, *nextipo;
1295255332Scy	void *pnext;
1296170263Sdarrenr	int err;
1297170263Sdarrenr
1298170263Sdarrenr	err = 0;
1299170263Sdarrenr	node = NULL;
1300170263Sdarrenr	nextnode = NULL;
1301170263Sdarrenr	ipo = NULL;
1302170263Sdarrenr	nextipo = NULL;
1303170263Sdarrenr
1304255332Scy	READ_ENTER(&softc->ipf_poolrw);
1305170263Sdarrenr
1306170263Sdarrenr	switch (ilp->ili_otype)
1307170263Sdarrenr	{
1308170263Sdarrenr	case IPFLOOKUPITER_LIST :
1309170263Sdarrenr		ipo = token->ipt_data;
1310170263Sdarrenr		if (ipo == NULL) {
1311255332Scy			nextipo = softp->ipf_pool_list[(int)ilp->ili_unit + 1];
1312170263Sdarrenr		} else {
1313170263Sdarrenr			nextipo = ipo->ipo_next;
1314170263Sdarrenr		}
1315170263Sdarrenr
1316170263Sdarrenr		if (nextipo != NULL) {
1317255332Scy			ATOMIC_INC32(nextipo->ipo_ref);
1318172771Sdarrenr			token->ipt_data = nextipo;
1319170263Sdarrenr		} else {
1320170263Sdarrenr			bzero((char *)&zp, sizeof(zp));
1321170263Sdarrenr			nextipo = &zp;
1322172771Sdarrenr			token->ipt_data = NULL;
1323170263Sdarrenr		}
1324255332Scy		pnext = nextipo->ipo_next;
1325170263Sdarrenr		break;
1326170263Sdarrenr
1327170263Sdarrenr	case IPFLOOKUPITER_NODE :
1328170263Sdarrenr		node = token->ipt_data;
1329170263Sdarrenr		if (node == NULL) {
1330255332Scy			ipo = ipf_pool_exists(arg, ilp->ili_unit,
1331255332Scy					      ilp->ili_name);
1332255332Scy			if (ipo == NULL) {
1333255332Scy				IPFERROR(70010);
1334170263Sdarrenr				err = ESRCH;
1335255332Scy			} else {
1336170263Sdarrenr				nextnode = ipo->ipo_list;
1337170263Sdarrenr				ipo = NULL;
1338170263Sdarrenr			}
1339170263Sdarrenr		} else {
1340170263Sdarrenr			nextnode = node->ipn_next;
1341170263Sdarrenr		}
1342170263Sdarrenr
1343170263Sdarrenr		if (nextnode != NULL) {
1344255332Scy			ATOMIC_INC32(nextnode->ipn_ref);
1345172771Sdarrenr			token->ipt_data = nextnode;
1346170263Sdarrenr		} else {
1347170263Sdarrenr			bzero((char *)&zn, sizeof(zn));
1348170263Sdarrenr			nextnode = &zn;
1349172771Sdarrenr			token->ipt_data = NULL;
1350170263Sdarrenr		}
1351255332Scy		pnext = nextnode->ipn_next;
1352170263Sdarrenr		break;
1353255332Scy
1354170263Sdarrenr	default :
1355255332Scy		IPFERROR(70011);
1356255332Scy		pnext = NULL;
1357170263Sdarrenr		err = EINVAL;
1358170263Sdarrenr		break;
1359170263Sdarrenr	}
1360170263Sdarrenr
1361255332Scy	RWLOCK_EXIT(&softc->ipf_poolrw);
1362170263Sdarrenr	if (err != 0)
1363170263Sdarrenr		return err;
1364170263Sdarrenr
1365170263Sdarrenr	switch (ilp->ili_otype)
1366170263Sdarrenr	{
1367170263Sdarrenr	case IPFLOOKUPITER_LIST :
1368255332Scy		err = COPYOUT(nextipo, ilp->ili_data, sizeof(*nextipo));
1369255332Scy		if (err != 0)  {
1370255332Scy			IPFERROR(70012);
1371255332Scy			err = EFAULT;
1372255332Scy		}
1373170263Sdarrenr		if (ipo != NULL) {
1374255332Scy			WRITE_ENTER(&softc->ipf_poolrw);
1375255332Scy			ipf_pool_deref(softc, softp, ipo);
1376255332Scy			RWLOCK_EXIT(&softc->ipf_poolrw);
1377170263Sdarrenr		}
1378170263Sdarrenr		break;
1379170263Sdarrenr
1380170263Sdarrenr	case IPFLOOKUPITER_NODE :
1381255332Scy		err = COPYOUT(nextnode, ilp->ili_data, sizeof(*nextnode));
1382255332Scy		if (err != 0) {
1383255332Scy			IPFERROR(70013);
1384255332Scy			err = EFAULT;
1385255332Scy		}
1386170263Sdarrenr		if (node != NULL) {
1387255332Scy			WRITE_ENTER(&softc->ipf_poolrw);
1388255332Scy			ipf_pool_node_deref(softp, node);
1389255332Scy			RWLOCK_EXIT(&softc->ipf_poolrw);
1390170263Sdarrenr		}
1391170263Sdarrenr		break;
1392170263Sdarrenr	}
1393255332Scy	if (pnext == NULL)
1394255332Scy		ipf_token_mark_complete(token);
1395170263Sdarrenr
1396170263Sdarrenr	return err;
1397170263Sdarrenr}
1398170263Sdarrenr
1399170263Sdarrenr
1400170263Sdarrenr/* ------------------------------------------------------------------------ */
1401255332Scy/* Function:    ipf_pool_iterderef                                          */
1402170263Sdarrenr/* Returns:     void                                                        */
1403255332Scy/* Parameters:  softc(I) - pointer to soft context main structure           */
1404255332Scy/*              arg(I)   - pointer to local context to use                  */
1405255332Scy/*              unit(I)  - ipfilter device to which we are working on       */
1406255332Scy/* Locks:       WRITE(ipf_poolrw)                                           */
1407170263Sdarrenr/*                                                                          */
1408170263Sdarrenr/* ------------------------------------------------------------------------ */
1409255332Scystatic int
1410255332Scyipf_pool_iter_deref(softc, arg, otype, unit, data)
1411255332Scy	ipf_main_softc_t *softc;
1412255332Scy	void *arg;
1413255332Scy	int otype;
1414255332Scy	int unit;
1415255332Scy	void *data;
1416170263Sdarrenr{
1417255332Scy	ipf_pool_softc_t *softp = arg;
1418170263Sdarrenr
1419170263Sdarrenr	if (data == NULL)
1420255332Scy		return EINVAL;
1421170263Sdarrenr
1422170263Sdarrenr	if (unit < 0 || unit > IPL_LOGMAX)
1423255332Scy		return EINVAL;
1424170263Sdarrenr
1425170263Sdarrenr	switch (otype)
1426170263Sdarrenr	{
1427170263Sdarrenr	case IPFLOOKUPITER_LIST :
1428255332Scy		ipf_pool_deref(softc, softp, (ip_pool_t *)data);
1429170263Sdarrenr		break;
1430170263Sdarrenr
1431170263Sdarrenr	case IPFLOOKUPITER_NODE :
1432255332Scy		ipf_pool_node_deref(softp, (ip_pool_node_t *)data);
1433170263Sdarrenr		break;
1434170263Sdarrenr	default :
1435170263Sdarrenr		break;
1436170263Sdarrenr	}
1437255332Scy
1438255332Scy	return 0;
1439170263Sdarrenr}
1440170263Sdarrenr
1441170263Sdarrenr
1442255332Scy/* ------------------------------------------------------------------------ */
1443255332Scy/* Function:    ipf_pool_expire                                             */
1444255332Scy/* Returns:     Nil                                                         */
1445255332Scy/* Parameters:  softc(I) - pointer to soft context main structure           */
1446255332Scy/*              arg(I)   - pointer to local context to use                  */
1447255332Scy/*                                                                          */
1448255332Scy/* At present this function exists just to support temporary addition of    */
1449255332Scy/* nodes to the address pool.                                               */
1450255332Scy/* ------------------------------------------------------------------------ */
1451255332Scystatic void
1452255332Scyipf_pool_expire(softc, arg)
1453255332Scy	ipf_main_softc_t *softc;
1454255332Scy	void *arg;
1455145516Sdarrenr{
1456255332Scy	ipf_pool_softc_t *softp = arg;
1457255332Scy	ip_pool_node_t *n;
1458145516Sdarrenr
1459255332Scy	while ((n = softp->ipf_node_explist) != NULL) {
1460255332Scy		/*
1461255332Scy		 * Because the list is kept sorted on insertion, the fist
1462255332Scy		 * one that dies in the future means no more work to do.
1463255332Scy		 */
1464255332Scy		if (n->ipn_die > softc->ipf_ticks)
1465255332Scy			break;
1466255332Scy		ipf_pool_remove_node(softc, softp, n->ipn_owner, n);
1467145516Sdarrenr	}
1468145516Sdarrenr}
1469145516Sdarrenr
1470145516Sdarrenr
1471255332Scy
1472255332Scy
1473255332Scy#ifndef _KERNEL
1474145516Sdarrenrvoid
1475255332Scyipf_pool_dump(softc, arg)
1476255332Scy	ipf_main_softc_t *softc;
1477255332Scy	void *arg;
1478145516Sdarrenr{
1479255332Scy	ipf_pool_softc_t *softp = arg;
1480255332Scy	ip_pool_t *ipl;
1481255332Scy	int i;
1482145516Sdarrenr
1483255332Scy	printf("List of configured pools\n");
1484255332Scy	for (i = 0; i <= LOOKUP_POOL_MAX; i++)
1485255332Scy		for (ipl = softp->ipf_pool_list[i]; ipl != NULL;
1486255332Scy		     ipl = ipl->ipo_next)
1487255332Scy			printpool(ipl, bcopywrap, NULL, opts, NULL);
1488145516Sdarrenr}
1489255332Scy#endif
1490