1145516Sdarrenr/*
2145516Sdarrenr * Copyright (C) 1993-2001, 2003 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>
36145516Sdarrenr#if !defined(linux)
37145516Sdarrenr# include <sys/protosw.h>
38145516Sdarrenr#endif
39145516Sdarrenr#include <sys/socket.h>
40145516Sdarrenr#if defined(_KERNEL) && (!defined(__SVR4) && !defined(__svr4__))
41145516Sdarrenr# include <sys/mbuf.h>
42145516Sdarrenr#endif
43145516Sdarrenr#if defined(__SVR4) || defined(__svr4__)
44145516Sdarrenr# include <sys/filio.h>
45145516Sdarrenr# include <sys/byteorder.h>
46145516Sdarrenr# ifdef _KERNEL
47145516Sdarrenr#  include <sys/dditypes.h>
48145516Sdarrenr# endif
49145516Sdarrenr# include <sys/stream.h>
50145516Sdarrenr# include <sys/kmem.h>
51145516Sdarrenr#endif
52145516Sdarrenr#if defined(__FreeBSD_version) && (__FreeBSD_version >= 300000)
53145516Sdarrenr# include <sys/malloc.h>
54145516Sdarrenr#endif
55145516Sdarrenr
56172771Sdarrenr#if defined(SOLARIS2) && !defined(_KERNEL)
57172771Sdarrenr# include "radix_ipf.h"
58172771Sdarrenr#endif
59153872Sguido#if defined(_KERNEL) && (defined(__osf__) || defined(AIX) || \
60153872Sguido     defined(__hpux) || defined(__sgi))
61145516Sdarrenr# include "radix_ipf_local.h"
62145516Sdarrenr# define _RADIX_H_
63145516Sdarrenr#endif
64145516Sdarrenr#include <net/if.h>
65145516Sdarrenr#include <netinet/in.h>
66145516Sdarrenr
67145516Sdarrenr#include "netinet/ip_compat.h"
68145516Sdarrenr#include "netinet/ip_fil.h"
69145516Sdarrenr#include "netinet/ip_pool.h"
70145516Sdarrenr
71145516Sdarrenr#if defined(IPFILTER_LOOKUP) && defined(_KERNEL) && \
72145516Sdarrenr      ((BSD >= 198911) && !defined(__osf__) && \
73145516Sdarrenr      !defined(__hpux) && !defined(__sgi))
74145516Sdarrenrstatic int rn_freenode __P((struct radix_node *, void *));
75145516Sdarrenr#endif
76145516Sdarrenr
77145516Sdarrenr/* END OF INCLUDES */
78145516Sdarrenr
79145516Sdarrenr#if !defined(lint)
80145516Sdarrenrstatic const char sccsid[] = "@(#)ip_fil.c	2.41 6/5/96 (C) 1993-2000 Darren Reed";
81172771Sdarrenrstatic const char rcsid[] = "@(#)$Id: ip_pool.c,v 2.55.2.24 2007/10/10 09:45:37 darrenr Exp $";
82145516Sdarrenr#endif
83145516Sdarrenr
84145516Sdarrenr#ifdef IPFILTER_LOOKUP
85145516Sdarrenr
86172771Sdarrenr# if !defined(RADIX_NODE_HEAD_LOCK) || !defined(RADIX_NODE_HEAD_UNLOCK) || \
87172771Sdarrenr     !defined(_KERNEL)
88172771Sdarrenr#  undef RADIX_NODE_HEAD_LOCK
89172771Sdarrenr#  undef RADIX_NODE_HEAD_UNLOCK
90145516Sdarrenr#  define RADIX_NODE_HEAD_LOCK(x)	;
91145516Sdarrenr#  define RADIX_NODE_HEAD_UNLOCK(x)	;
92145516Sdarrenr# endif
93145516Sdarrenr
94170263Sdarrenrstatic void ip_pool_clearnodes __P((ip_pool_t *));
95170263Sdarrenrstatic void *ip_pool_exists __P((int, char *));
96170263Sdarrenr
97145516Sdarrenrip_pool_stat_t ipoolstat;
98145516Sdarrenripfrwlock_t ip_poolrw;
99145516Sdarrenr
100145516Sdarrenr/*
101145516Sdarrenr * Binary tree routines from Sedgewick and enhanced to do ranges of addresses.
102145516Sdarrenr * NOTE: Insertion *MUST* be from greatest range to least for it to work!
103145516Sdarrenr * These should be replaced, eventually, by something else - most notably a
104145516Sdarrenr * interval searching method.  The important feature is to be able to find
105145516Sdarrenr * the best match.
106145516Sdarrenr *
107145516Sdarrenr * So why not use a radix tree for this?  As the first line implies, it
108145516Sdarrenr * has been written to work with a _range_ of addresses.  A range is not
109145516Sdarrenr * necessarily a match with any given netmask so what we end up dealing
110145516Sdarrenr * with is an interval tree.  Implementations of these are hard to find
111145516Sdarrenr * and the one herein is far from bug free.
112145516Sdarrenr *
113145516Sdarrenr * Sigh, in the end I became convinced that the bugs the code contained did
114145516Sdarrenr * not make it worthwhile not using radix trees.  For now the radix tree from
115145516Sdarrenr * 4.4 BSD is used, but this is not viewed as a long term solution.
116145516Sdarrenr */
117145516Sdarrenrip_pool_t *ip_pool_list[IPL_LOGSIZE] = { NULL, NULL, NULL, NULL,
118145516Sdarrenr					 NULL, NULL, NULL, NULL };
119145516Sdarrenr
120145516Sdarrenr
121145516Sdarrenr#ifdef TEST_POOL
122145516Sdarrenrvoid treeprint __P((ip_pool_t *));
123145516Sdarrenr
124145516Sdarrenrint
125145516Sdarrenrmain(argc, argv)
126145516Sdarrenr	int argc;
127145516Sdarrenr	char *argv[];
128145516Sdarrenr{
129145516Sdarrenr	addrfamily_t a, b;
130145516Sdarrenr	iplookupop_t op;
131145516Sdarrenr	ip_pool_t *ipo;
132145516Sdarrenr	i6addr_t ip;
133145516Sdarrenr
134145516Sdarrenr	RWLOCK_INIT(&ip_poolrw, "poolrw");
135145516Sdarrenr	ip_pool_init();
136145516Sdarrenr
137145516Sdarrenr	bzero((char *)&a, sizeof(a));
138145516Sdarrenr	bzero((char *)&b, sizeof(b));
139145516Sdarrenr	bzero((char *)&ip, sizeof(ip));
140145516Sdarrenr	bzero((char *)&op, sizeof(op));
141145516Sdarrenr	strcpy(op.iplo_name, "0");
142145516Sdarrenr
143145516Sdarrenr	if (ip_pool_create(&op) == 0)
144170263Sdarrenr		ipo = ip_pool_exists(0, "0");
145145516Sdarrenr
146145516Sdarrenr	a.adf_addr.in4.s_addr = 0x0a010203;
147145516Sdarrenr	b.adf_addr.in4.s_addr = 0xffffffff;
148145516Sdarrenr	ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 1);
149145516Sdarrenr	ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 1);
150145516Sdarrenr
151145516Sdarrenr	a.adf_addr.in4.s_addr = 0x0a000000;
152145516Sdarrenr	b.adf_addr.in4.s_addr = 0xff000000;
153145516Sdarrenr	ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 0);
154145516Sdarrenr	ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 0);
155145516Sdarrenr
156145516Sdarrenr	a.adf_addr.in4.s_addr = 0x0a010100;
157145516Sdarrenr	b.adf_addr.in4.s_addr = 0xffffff00;
158145516Sdarrenr	ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 1);
159145516Sdarrenr	ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 1);
160145516Sdarrenr
161145516Sdarrenr	a.adf_addr.in4.s_addr = 0x0a010200;
162145516Sdarrenr	b.adf_addr.in4.s_addr = 0xffffff00;
163145516Sdarrenr	ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 0);
164145516Sdarrenr	ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 0);
165145516Sdarrenr
166145516Sdarrenr	a.adf_addr.in4.s_addr = 0x0a010000;
167145516Sdarrenr	b.adf_addr.in4.s_addr = 0xffff0000;
168145516Sdarrenr	ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 1);
169145516Sdarrenr	ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 1);
170145516Sdarrenr
171145516Sdarrenr	a.adf_addr.in4.s_addr = 0x0a01020f;
172145516Sdarrenr	b.adf_addr.in4.s_addr = 0xffffffff;
173145516Sdarrenr	ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 1);
174145516Sdarrenr	ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 1);
175145516Sdarrenr#ifdef	DEBUG_POOL
176145516Sdarrenrtreeprint(ipo);
177145516Sdarrenr#endif
178145516Sdarrenr	ip.in4.s_addr = 0x0a00aabb;
179145516Sdarrenr	printf("search(%#x) = %d (0)\n", ip.in4.s_addr,
180145516Sdarrenr		ip_pool_search(ipo, 4, &ip));
181145516Sdarrenr
182145516Sdarrenr	ip.in4.s_addr = 0x0a000001;
183145516Sdarrenr	printf("search(%#x) = %d (0)\n", ip.in4.s_addr,
184145516Sdarrenr		ip_pool_search(ipo, 4, &ip));
185145516Sdarrenr
186145516Sdarrenr	ip.in4.s_addr = 0x0a000101;
187145516Sdarrenr	printf("search(%#x) = %d (0)\n", ip.in4.s_addr,
188145516Sdarrenr		ip_pool_search(ipo, 4, &ip));
189145516Sdarrenr
190145516Sdarrenr	ip.in4.s_addr = 0x0a010001;
191145516Sdarrenr	printf("search(%#x) = %d (1)\n", ip.in4.s_addr,
192145516Sdarrenr		ip_pool_search(ipo, 4, &ip));
193145516Sdarrenr
194145516Sdarrenr	ip.in4.s_addr = 0x0a010101;
195145516Sdarrenr	printf("search(%#x) = %d (1)\n", ip.in4.s_addr,
196145516Sdarrenr		ip_pool_search(ipo, 4, &ip));
197145516Sdarrenr
198145516Sdarrenr	ip.in4.s_addr = 0x0a010201;
199145516Sdarrenr	printf("search(%#x) = %d (0)\n", ip.in4.s_addr,
200145516Sdarrenr		ip_pool_search(ipo, 4, &ip));
201145516Sdarrenr
202145516Sdarrenr	ip.in4.s_addr = 0x0a010203;
203145516Sdarrenr	printf("search(%#x) = %d (1)\n", ip.in4.s_addr,
204145516Sdarrenr		ip_pool_search(ipo, 4, &ip));
205145516Sdarrenr
206145516Sdarrenr	ip.in4.s_addr = 0x0a01020f;
207145516Sdarrenr	printf("search(%#x) = %d (1)\n", ip.in4.s_addr,
208145516Sdarrenr		ip_pool_search(ipo, 4, &ip));
209145516Sdarrenr
210145516Sdarrenr	ip.in4.s_addr = 0x0b00aabb;
211145516Sdarrenr	printf("search(%#x) = %d (-1)\n", ip.in4.s_addr,
212145516Sdarrenr		ip_pool_search(ipo, 4, &ip));
213145516Sdarrenr
214145516Sdarrenr#ifdef	DEBUG_POOL
215145516Sdarrenrtreeprint(ipo);
216145516Sdarrenr#endif
217145516Sdarrenr
218145516Sdarrenr	ip_pool_fini();
219145516Sdarrenr
220145516Sdarrenr	return 0;
221145516Sdarrenr}
222145516Sdarrenr
223145516Sdarrenr
224145516Sdarrenrvoid
225145516Sdarrenrtreeprint(ipo)
226145516Sdarrenrip_pool_t *ipo;
227145516Sdarrenr{
228145516Sdarrenr	ip_pool_node_t *c;
229145516Sdarrenr
230145516Sdarrenr	for (c = ipo->ipo_list; c != NULL; c = c->ipn_next)
231145516Sdarrenr		printf("Node %p(%s) (%#x/%#x) = %d hits %lu\n",
232145516Sdarrenr			c, c->ipn_name, c->ipn_addr.adf_addr.in4.s_addr,
233145516Sdarrenr			c->ipn_mask.adf_addr.in4.s_addr,
234145516Sdarrenr			c->ipn_info, c->ipn_hits);
235145516Sdarrenr}
236145516Sdarrenr#endif /* TEST_POOL */
237145516Sdarrenr
238145516Sdarrenr
239145516Sdarrenr/* ------------------------------------------------------------------------ */
240145516Sdarrenr/* Function:    ip_pool_init                                                */
241145516Sdarrenr/* Returns:     int     - 0 = success, else error                           */
242145516Sdarrenr/*                                                                          */
243145516Sdarrenr/* Initialise the routing table data structures where required.             */
244145516Sdarrenr/* ------------------------------------------------------------------------ */
245145516Sdarrenrint ip_pool_init()
246145516Sdarrenr{
247145516Sdarrenr
248145516Sdarrenr	bzero((char *)&ipoolstat, sizeof(ipoolstat));
249145516Sdarrenr
250145516Sdarrenr#if (!defined(_KERNEL) || (BSD < 199306))
251145516Sdarrenr	rn_init();
252145516Sdarrenr#endif
253145516Sdarrenr	return 0;
254145516Sdarrenr}
255145516Sdarrenr
256145516Sdarrenr
257145516Sdarrenr/* ------------------------------------------------------------------------ */
258145516Sdarrenr/* Function:    ip_pool_fini                                                */
259145516Sdarrenr/* Returns:     int     - 0 = success, else error                           */
260145516Sdarrenr/* Locks:       WRITE(ipf_global)                                           */
261145516Sdarrenr/*                                                                          */
262145516Sdarrenr/* Clean up all the pool data structures allocated and call the cleanup     */
263145516Sdarrenr/* function for the radix tree that supports the pools. ip_pool_destroy() is*/
264145516Sdarrenr/* used to delete the pools one by one to ensure they're properly freed up. */
265145516Sdarrenr/* ------------------------------------------------------------------------ */
266145516Sdarrenrvoid ip_pool_fini()
267145516Sdarrenr{
268145516Sdarrenr	ip_pool_t *p, *q;
269145516Sdarrenr	int i;
270145516Sdarrenr
271145516Sdarrenr	for (i = 0; i <= IPL_LOGMAX; i++) {
272145516Sdarrenr		for (q = ip_pool_list[i]; (p = q) != NULL; ) {
273145516Sdarrenr			q = p->ipo_next;
274170263Sdarrenr			(void) ip_pool_destroy(i, p->ipo_name);
275145516Sdarrenr		}
276145516Sdarrenr	}
277145516Sdarrenr
278145516Sdarrenr#if (!defined(_KERNEL) || (BSD < 199306))
279145516Sdarrenr	rn_fini();
280145516Sdarrenr#endif
281145516Sdarrenr}
282145516Sdarrenr
283145516Sdarrenr
284145516Sdarrenr/* ------------------------------------------------------------------------ */
285145516Sdarrenr/* Function:    ip_pool_statistics                                          */
286145516Sdarrenr/* Returns:     int     - 0 = success, else error                           */
287145516Sdarrenr/* Parameters:  op(I)   - pointer to lookup operation arguments             */
288145516Sdarrenr/*                                                                          */
289145516Sdarrenr/* Copy the current statistics out into user space, collecting pool list    */
290145516Sdarrenr/* pointers as appropriate for later use.                                   */
291145516Sdarrenr/* ------------------------------------------------------------------------ */
292145516Sdarrenrint ip_pool_statistics(op)
293145516Sdarrenriplookupop_t *op;
294145516Sdarrenr{
295145516Sdarrenr	ip_pool_stat_t stats;
296145516Sdarrenr	int unit, i, err = 0;
297145516Sdarrenr
298145516Sdarrenr	if (op->iplo_size != sizeof(ipoolstat))
299145516Sdarrenr		return EINVAL;
300145516Sdarrenr
301145516Sdarrenr	bcopy((char *)&ipoolstat, (char *)&stats, sizeof(stats));
302145516Sdarrenr	unit = op->iplo_unit;
303145516Sdarrenr	if (unit == IPL_LOGALL) {
304145516Sdarrenr		for (i = 0; i < IPL_LOGSIZE; i++)
305145516Sdarrenr			stats.ipls_list[i] = ip_pool_list[i];
306145516Sdarrenr	} else if (unit >= 0 && unit < IPL_LOGSIZE) {
307145516Sdarrenr		if (op->iplo_name[0] != '\0')
308170263Sdarrenr			stats.ipls_list[unit] = ip_pool_exists(unit,
309170263Sdarrenr							       op->iplo_name);
310145516Sdarrenr		else
311145516Sdarrenr			stats.ipls_list[unit] = ip_pool_list[unit];
312145516Sdarrenr	} else
313145516Sdarrenr		err = EINVAL;
314145516Sdarrenr	if (err == 0)
315145516Sdarrenr		err = COPYOUT(&stats, op->iplo_struct, sizeof(stats));
316145516Sdarrenr	return err;
317145516Sdarrenr}
318145516Sdarrenr
319145516Sdarrenr
320145516Sdarrenr/* ------------------------------------------------------------------------ */
321170263Sdarrenr/* Function:    ip_pool_exists                                              */
322145516Sdarrenr/* Returns:     int     - 0 = success, else error                           */
323145516Sdarrenr/* Parameters:  ipo(I)  - pointer to the pool getting the new node.         */
324145516Sdarrenr/*                                                                          */
325145516Sdarrenr/* Find a matching pool inside the collection of pools for a particular     */
326145516Sdarrenr/* device, indicated by the unit number.                                    */
327145516Sdarrenr/* ------------------------------------------------------------------------ */
328170263Sdarrenrstatic void *ip_pool_exists(unit, name)
329145516Sdarrenrint unit;
330145516Sdarrenrchar *name;
331145516Sdarrenr{
332145516Sdarrenr	ip_pool_t *p;
333145516Sdarrenr
334145516Sdarrenr	for (p = ip_pool_list[unit]; p != NULL; p = p->ipo_next)
335145516Sdarrenr		if (strncmp(p->ipo_name, name, sizeof(p->ipo_name)) == 0)
336145516Sdarrenr			break;
337145516Sdarrenr	return p;
338145516Sdarrenr}
339145516Sdarrenr
340145516Sdarrenr
341145516Sdarrenr/* ------------------------------------------------------------------------ */
342170263Sdarrenr/* Function:    ip_pool_find                                                */
343170263Sdarrenr/* Returns:     int     - 0 = success, else error                           */
344170263Sdarrenr/* Parameters:  ipo(I)  - pointer to the pool getting the new node.         */
345170263Sdarrenr/*                                                                          */
346170263Sdarrenr/* Find a matching pool inside the collection of pools for a particular     */
347170263Sdarrenr/* device, indicated by the unit number.  If it is marked for deletion then */
348170263Sdarrenr/* pretend it does not exist.                                               */
349170263Sdarrenr/* ------------------------------------------------------------------------ */
350170263Sdarrenrvoid *ip_pool_find(unit, name)
351170263Sdarrenrint unit;
352170263Sdarrenrchar *name;
353170263Sdarrenr{
354170263Sdarrenr	ip_pool_t *p;
355170263Sdarrenr
356170263Sdarrenr	p = ip_pool_exists(unit, name);
357170263Sdarrenr	if ((p != NULL) && (p->ipo_flags & IPOOL_DELETE))
358170263Sdarrenr		return NULL;
359170263Sdarrenr
360170263Sdarrenr	return p;
361170263Sdarrenr}
362170263Sdarrenr
363170263Sdarrenr
364170263Sdarrenr/* ------------------------------------------------------------------------ */
365145516Sdarrenr/* Function:    ip_pool_findeq                                              */
366145516Sdarrenr/* Returns:     int     - 0 = success, else error                           */
367145516Sdarrenr/* Parameters:  ipo(I)  - pointer to the pool getting the new node.         */
368145516Sdarrenr/*              addr(I) - pointer to address information to delete          */
369145516Sdarrenr/*              mask(I) -                                                   */
370145516Sdarrenr/*                                                                          */
371145516Sdarrenr/* Searches for an exact match of an entry in the pool.                     */
372145516Sdarrenr/* ------------------------------------------------------------------------ */
373145516Sdarrenrip_pool_node_t *ip_pool_findeq(ipo, addr, mask)
374145516Sdarrenrip_pool_t *ipo;
375145516Sdarrenraddrfamily_t *addr, *mask;
376145516Sdarrenr{
377145516Sdarrenr	struct radix_node *n;
378153872Sguido	SPL_INT(s);
379145516Sdarrenr
380145516Sdarrenr	SPL_NET(s);
381145516Sdarrenr	RADIX_NODE_HEAD_LOCK(ipo->ipo_head);
382145516Sdarrenr	n = ipo->ipo_head->rnh_lookup(addr, mask, ipo->ipo_head);
383145516Sdarrenr	RADIX_NODE_HEAD_UNLOCK(ipo->ipo_head);
384145516Sdarrenr	SPL_X(s);
385145516Sdarrenr	return (ip_pool_node_t *)n;
386145516Sdarrenr}
387145516Sdarrenr
388145516Sdarrenr
389145516Sdarrenr/* ------------------------------------------------------------------------ */
390145516Sdarrenr/* Function:    ip_pool_search                                              */
391145516Sdarrenr/* Returns:     int     - 0 == +ve match, -1 == error, 1 == -ve/no match    */
392145516Sdarrenr/* Parameters:  tptr(I)    - pointer to the pool to search                  */
393145516Sdarrenr/*              version(I) - IP protocol version (4 or 6)                   */
394145516Sdarrenr/*              dptr(I)    - pointer to address information                 */
395145516Sdarrenr/*                                                                          */
396145516Sdarrenr/* Search the pool for a given address and return a search result.          */
397145516Sdarrenr/* ------------------------------------------------------------------------ */
398170263Sdarrenrint ip_pool_search(tptr, ipversion, dptr)
399145516Sdarrenrvoid *tptr;
400170263Sdarrenrint ipversion;
401145516Sdarrenrvoid *dptr;
402145516Sdarrenr{
403145516Sdarrenr	struct radix_node *rn;
404145516Sdarrenr	ip_pool_node_t *m;
405145516Sdarrenr	i6addr_t *addr;
406145516Sdarrenr	addrfamily_t v;
407145516Sdarrenr	ip_pool_t *ipo;
408145516Sdarrenr	int rv;
409145516Sdarrenr
410145516Sdarrenr	ipo = tptr;
411145516Sdarrenr	if (ipo == NULL)
412145516Sdarrenr		return -1;
413145516Sdarrenr
414145516Sdarrenr	rv = 1;
415145516Sdarrenr	m = NULL;
416145516Sdarrenr	addr = (i6addr_t *)dptr;
417145516Sdarrenr	bzero(&v, sizeof(v));
418145516Sdarrenr	v.adf_len = offsetof(addrfamily_t, adf_addr);
419145516Sdarrenr
420170263Sdarrenr	if (ipversion == 4) {
421145516Sdarrenr		v.adf_len += sizeof(addr->in4);
422145516Sdarrenr		v.adf_addr.in4 = addr->in4;
423145516Sdarrenr#ifdef USE_INET6
424170263Sdarrenr	} else if (ipversion == 6) {
425145516Sdarrenr		v.adf_len += sizeof(addr->in6);
426145516Sdarrenr		v.adf_addr.in6 = addr->in6;
427145516Sdarrenr#endif
428145516Sdarrenr	} else
429145516Sdarrenr		return -1;
430145516Sdarrenr
431145516Sdarrenr	READ_ENTER(&ip_poolrw);
432145516Sdarrenr
433145516Sdarrenr	RADIX_NODE_HEAD_LOCK(ipo->ipo_head);
434145516Sdarrenr	rn = ipo->ipo_head->rnh_matchaddr(&v, ipo->ipo_head);
435145516Sdarrenr	RADIX_NODE_HEAD_UNLOCK(ipo->ipo_head);
436145516Sdarrenr
437145516Sdarrenr	if ((rn != NULL) && ((rn->rn_flags & RNF_ROOT) == 0)) {
438145516Sdarrenr		m = (ip_pool_node_t *)rn;
439145516Sdarrenr		ipo->ipo_hits++;
440145516Sdarrenr		m->ipn_hits++;
441145516Sdarrenr		rv = m->ipn_info;
442145516Sdarrenr	}
443145516Sdarrenr	RWLOCK_EXIT(&ip_poolrw);
444145516Sdarrenr	return rv;
445145516Sdarrenr}
446145516Sdarrenr
447145516Sdarrenr
448145516Sdarrenr/* ------------------------------------------------------------------------ */
449145516Sdarrenr/* Function:    ip_pool_insert                                              */
450145516Sdarrenr/* Returns:     int     - 0 = success, else error                           */
451145516Sdarrenr/* Parameters:  ipo(I)  - pointer to the pool getting the new node.         */
452145516Sdarrenr/*              addr(I) - address being added as a node                     */
453145516Sdarrenr/*              mask(I) - netmask to with the node being added              */
454145516Sdarrenr/*              info(I) - extra information to store in this node.          */
455145516Sdarrenr/* Locks:       WRITE(ip_poolrw)                                            */
456145516Sdarrenr/*                                                                          */
457145516Sdarrenr/* Add another node to the pool given by ipo.  The three parameters passed  */
458145516Sdarrenr/* in (addr, mask, info) shold all be stored in the node.                   */
459145516Sdarrenr/* ------------------------------------------------------------------------ */
460145516Sdarrenrint ip_pool_insert(ipo, addr, mask, info)
461145516Sdarrenrip_pool_t *ipo;
462145516Sdarrenri6addr_t *addr, *mask;
463145516Sdarrenrint info;
464145516Sdarrenr{
465145516Sdarrenr	struct radix_node *rn;
466145516Sdarrenr	ip_pool_node_t *x;
467145516Sdarrenr
468145516Sdarrenr	KMALLOC(x, ip_pool_node_t *);
469145516Sdarrenr	if (x == NULL) {
470145516Sdarrenr		return ENOMEM;
471145516Sdarrenr	}
472145516Sdarrenr
473145516Sdarrenr	bzero(x, sizeof(*x));
474145516Sdarrenr
475145516Sdarrenr	x->ipn_info = info;
476145516Sdarrenr	(void)strncpy(x->ipn_name, ipo->ipo_name, sizeof(x->ipn_name));
477145516Sdarrenr
478145516Sdarrenr	bcopy(addr, &x->ipn_addr.adf_addr, sizeof(*addr));
479145516Sdarrenr	x->ipn_addr.adf_len = sizeof(x->ipn_addr);
480145516Sdarrenr	bcopy(mask, &x->ipn_mask.adf_addr, sizeof(*mask));
481145516Sdarrenr	x->ipn_mask.adf_len = sizeof(x->ipn_mask);
482145516Sdarrenr
483145516Sdarrenr	RADIX_NODE_HEAD_LOCK(ipo->ipo_head);
484145516Sdarrenr	rn = ipo->ipo_head->rnh_addaddr(&x->ipn_addr, &x->ipn_mask,
485145516Sdarrenr					ipo->ipo_head, x->ipn_nodes);
486145516Sdarrenr	RADIX_NODE_HEAD_UNLOCK(ipo->ipo_head);
487145516Sdarrenr#ifdef	DEBUG_POOL
488145516Sdarrenr	printf("Added %p at %p\n", x, rn);
489145516Sdarrenr#endif
490145516Sdarrenr
491145516Sdarrenr	if (rn == NULL) {
492145516Sdarrenr		KFREE(x);
493145516Sdarrenr		return ENOMEM;
494145516Sdarrenr	}
495145516Sdarrenr
496170263Sdarrenr	x->ipn_ref = 1;
497145516Sdarrenr	x->ipn_next = ipo->ipo_list;
498145516Sdarrenr	x->ipn_pnext = &ipo->ipo_list;
499145516Sdarrenr	if (ipo->ipo_list != NULL)
500145516Sdarrenr		ipo->ipo_list->ipn_pnext = &x->ipn_next;
501145516Sdarrenr	ipo->ipo_list = x;
502145516Sdarrenr
503145516Sdarrenr	ipoolstat.ipls_nodes++;
504145516Sdarrenr
505145516Sdarrenr	return 0;
506145516Sdarrenr}
507145516Sdarrenr
508145516Sdarrenr
509145516Sdarrenr/* ------------------------------------------------------------------------ */
510145516Sdarrenr/* Function:    ip_pool_create                                              */
511145516Sdarrenr/* Returns:     int     - 0 = success, else error                           */
512145516Sdarrenr/* Parameters:  op(I) - pointer to iplookup struct with call details        */
513145516Sdarrenr/* Locks:       WRITE(ip_poolrw)                                            */
514145516Sdarrenr/*                                                                          */
515145516Sdarrenr/* Creates a new group according to the paramters passed in via the         */
516145516Sdarrenr/* iplookupop structure.  Does not check to see if the group already exists */
517145516Sdarrenr/* when being inserted - assume this has already been done.  If the pool is */
518145516Sdarrenr/* marked as being anonymous, give it a new, unique, identifier.  Call any  */
519145516Sdarrenr/* other functions required to initialise the structure.                    */
520170263Sdarrenr/*                                                                          */
521170263Sdarrenr/* If the structure is flagged for deletion then reset the flag and return, */
522170263Sdarrenr/* as this likely means we've tried to free a pool that is in use (flush)   */
523170263Sdarrenr/* and now want to repopulate it with "new" data.                           */
524145516Sdarrenr/* ------------------------------------------------------------------------ */
525145516Sdarrenrint ip_pool_create(op)
526145516Sdarrenriplookupop_t *op;
527145516Sdarrenr{
528145516Sdarrenr	char name[FR_GROUPLEN];
529145516Sdarrenr	int poolnum, unit;
530145516Sdarrenr	ip_pool_t *h;
531145516Sdarrenr
532170263Sdarrenr	unit = op->iplo_unit;
533145516Sdarrenr
534172771Sdarrenr	if ((op->iplo_arg & LOOKUP_ANON) == 0) {
535170263Sdarrenr		h = ip_pool_exists(unit, op->iplo_name);
536172771Sdarrenr		if (h != NULL) {
537172771Sdarrenr			if ((h->ipo_flags & IPOOL_DELETE) == 0)
538172771Sdarrenr				return EEXIST;
539170263Sdarrenr			h->ipo_flags &= ~IPOOL_DELETE;
540170263Sdarrenr			return 0;
541170263Sdarrenr		}
542172771Sdarrenr	}
543170263Sdarrenr
544172771Sdarrenr	KMALLOC(h, ip_pool_t *);
545172771Sdarrenr	if (h == NULL)
546172771Sdarrenr		return ENOMEM;
547172771Sdarrenr	bzero(h, sizeof(*h));
548172771Sdarrenr
549172771Sdarrenr	if (rn_inithead((void **)&h->ipo_head,
550172771Sdarrenr			offsetof(addrfamily_t, adf_addr) << 3) == 0) {
551172771Sdarrenr		KFREE(h);
552172771Sdarrenr		return ENOMEM;
553145516Sdarrenr	}
554145516Sdarrenr
555170263Sdarrenr	if ((op->iplo_arg & LOOKUP_ANON) != 0) {
556145516Sdarrenr		ip_pool_t *p;
557145516Sdarrenr
558170263Sdarrenr		h->ipo_flags |= IPOOL_ANON;
559170263Sdarrenr		poolnum = LOOKUP_ANON;
560145516Sdarrenr
561145516Sdarrenr#if defined(SNPRINTF) && defined(_KERNEL)
562145516Sdarrenr		SNPRINTF(name, sizeof(name), "%x", poolnum);
563145516Sdarrenr#else
564145516Sdarrenr		(void)sprintf(name, "%x", poolnum);
565145516Sdarrenr#endif
566145516Sdarrenr
567145516Sdarrenr		for (p = ip_pool_list[unit]; p != NULL; ) {
568145516Sdarrenr			if (strncmp(name, p->ipo_name,
569145516Sdarrenr				    sizeof(p->ipo_name)) == 0) {
570145516Sdarrenr				poolnum++;
571145516Sdarrenr#if defined(SNPRINTF) && defined(_KERNEL)
572145516Sdarrenr				SNPRINTF(name, sizeof(name), "%x", poolnum);
573145516Sdarrenr#else
574145516Sdarrenr				(void)sprintf(name, "%x", poolnum);
575145516Sdarrenr#endif
576145516Sdarrenr				p = ip_pool_list[unit];
577145516Sdarrenr			} else
578145516Sdarrenr				p = p->ipo_next;
579145516Sdarrenr		}
580145516Sdarrenr
581145516Sdarrenr		(void)strncpy(h->ipo_name, name, sizeof(h->ipo_name));
582153872Sguido		(void)strncpy(op->iplo_name, name, sizeof(op->iplo_name));
583145516Sdarrenr	} else {
584170263Sdarrenr		(void)strncpy(h->ipo_name, op->iplo_name, sizeof(h->ipo_name));
585145516Sdarrenr	}
586145516Sdarrenr
587172771Sdarrenr	h->ipo_ref = 1;
588172771Sdarrenr	h->ipo_list = NULL;
589172771Sdarrenr	h->ipo_unit = unit;
590172771Sdarrenr	h->ipo_next = ip_pool_list[unit];
591172771Sdarrenr	if (ip_pool_list[unit] != NULL)
592172771Sdarrenr		ip_pool_list[unit]->ipo_pnext = &h->ipo_next;
593172771Sdarrenr	h->ipo_pnext = &ip_pool_list[unit];
594172771Sdarrenr	ip_pool_list[unit] = h;
595145516Sdarrenr
596172771Sdarrenr	ipoolstat.ipls_pools++;
597145516Sdarrenr
598145516Sdarrenr	return 0;
599145516Sdarrenr}
600145516Sdarrenr
601145516Sdarrenr
602145516Sdarrenr/* ------------------------------------------------------------------------ */
603145516Sdarrenr/* Function:    ip_pool_remove                                              */
604145516Sdarrenr/* Returns:     int    - 0 = success, else error                            */
605145516Sdarrenr/* Parameters:  ipo(I) - pointer to the pool to remove the node from.       */
606145516Sdarrenr/*              ipe(I) - address being deleted as a node                    */
607145516Sdarrenr/* Locks:       WRITE(ip_poolrw)                                            */
608145516Sdarrenr/*                                                                          */
609170263Sdarrenr/* Remove a node from the pool given by ipo.                                */
610145516Sdarrenr/* ------------------------------------------------------------------------ */
611145516Sdarrenrint ip_pool_remove(ipo, ipe)
612145516Sdarrenrip_pool_t *ipo;
613145516Sdarrenrip_pool_node_t *ipe;
614145516Sdarrenr{
615145516Sdarrenr
616170263Sdarrenr	if (ipe->ipn_pnext != NULL)
617170263Sdarrenr		*ipe->ipn_pnext = ipe->ipn_next;
618170263Sdarrenr	if (ipe->ipn_next != NULL)
619170263Sdarrenr		ipe->ipn_next->ipn_pnext = ipe->ipn_pnext;
620145516Sdarrenr
621145516Sdarrenr	RADIX_NODE_HEAD_LOCK(ipo->ipo_head);
622170263Sdarrenr	ipo->ipo_head->rnh_deladdr(&ipe->ipn_addr, &ipe->ipn_mask,
623145516Sdarrenr				   ipo->ipo_head);
624145516Sdarrenr	RADIX_NODE_HEAD_UNLOCK(ipo->ipo_head);
625145516Sdarrenr
626170263Sdarrenr	ip_pool_node_deref(ipe);
627145516Sdarrenr
628145516Sdarrenr	return 0;
629145516Sdarrenr}
630145516Sdarrenr
631145516Sdarrenr
632145516Sdarrenr/* ------------------------------------------------------------------------ */
633145516Sdarrenr/* Function:    ip_pool_destroy                                             */
634145516Sdarrenr/* Returns:     int    - 0 = success, else error                            */
635145516Sdarrenr/* Parameters:  op(I)  -  information about the pool to remove              */
636145516Sdarrenr/* Locks:       WRITE(ip_poolrw) or WRITE(ipf_global)                       */
637145516Sdarrenr/*                                                                          */
638145516Sdarrenr/* Search for a pool using paramters passed in and if it's not otherwise    */
639170263Sdarrenr/* busy, free it.  If it is busy, clear all of its nodes, mark it for being */
640170263Sdarrenr/* deleted and return an error saying it is busy.                           */
641145516Sdarrenr/*                                                                          */
642170263Sdarrenr/* NOTE: Because this function is called out of ipfdetach() where ip_poolrw */
643145516Sdarrenr/* may not be initialised, we can't use an ASSERT to enforce the locking    */
644145516Sdarrenr/* assertion that one of the two (ip_poolrw,ipf_global) is held.            */
645145516Sdarrenr/* ------------------------------------------------------------------------ */
646170263Sdarrenrint ip_pool_destroy(unit, name)
647170263Sdarrenrint unit;
648170263Sdarrenrchar *name;
649145516Sdarrenr{
650145516Sdarrenr	ip_pool_t *ipo;
651145516Sdarrenr
652170263Sdarrenr	ipo = ip_pool_exists(unit, name);
653145516Sdarrenr	if (ipo == NULL)
654145516Sdarrenr		return ESRCH;
655145516Sdarrenr
656170263Sdarrenr	if (ipo->ipo_ref != 1) {
657170263Sdarrenr		ip_pool_clearnodes(ipo);
658170263Sdarrenr		ipo->ipo_flags |= IPOOL_DELETE;
659170263Sdarrenr		return 0;
660170263Sdarrenr	}
661145516Sdarrenr
662145516Sdarrenr	ip_pool_free(ipo);
663145516Sdarrenr	return 0;
664145516Sdarrenr}
665145516Sdarrenr
666145516Sdarrenr
667145516Sdarrenr/* ------------------------------------------------------------------------ */
668145516Sdarrenr/* Function:    ip_pool_flush                                               */
669145516Sdarrenr/* Returns:     int    - number of pools deleted                            */
670145516Sdarrenr/* Parameters:  fp(I)  - which pool(s) to flush                             */
671145516Sdarrenr/* Locks:       WRITE(ip_poolrw) or WRITE(ipf_global)                       */
672145516Sdarrenr/*                                                                          */
673145516Sdarrenr/* Free all pools associated with the device that matches the unit number   */
674145516Sdarrenr/* passed in with operation.                                                */
675145516Sdarrenr/*                                                                          */
676170263Sdarrenr/* NOTE: Because this function is called out of ipfdetach() where ip_poolrw */
677145516Sdarrenr/* may not be initialised, we can't use an ASSERT to enforce the locking    */
678145516Sdarrenr/* assertion that one of the two (ip_poolrw,ipf_global) is held.            */
679145516Sdarrenr/* ------------------------------------------------------------------------ */
680145516Sdarrenrint ip_pool_flush(fp)
681145516Sdarrenriplookupflush_t *fp;
682145516Sdarrenr{
683145516Sdarrenr	int i, num = 0, unit, err;
684145516Sdarrenr	ip_pool_t *p, *q;
685145516Sdarrenr	iplookupop_t op;
686145516Sdarrenr
687145516Sdarrenr	unit = fp->iplf_unit;
688145516Sdarrenr
689145516Sdarrenr	for (i = 0; i <= IPL_LOGMAX; i++) {
690145516Sdarrenr		if (unit != IPLT_ALL && i != unit)
691145516Sdarrenr			continue;
692145516Sdarrenr		for (q = ip_pool_list[i]; (p = q) != NULL; ) {
693145516Sdarrenr			op.iplo_unit = i;
694145516Sdarrenr			(void)strncpy(op.iplo_name, p->ipo_name,
695145516Sdarrenr				sizeof(op.iplo_name));
696145516Sdarrenr			q = p->ipo_next;
697170263Sdarrenr			err = ip_pool_destroy(op.iplo_unit, op.iplo_name);
698145516Sdarrenr			if (err == 0)
699145516Sdarrenr				num++;
700145516Sdarrenr			else
701145516Sdarrenr				break;
702145516Sdarrenr		}
703145516Sdarrenr	}
704145516Sdarrenr	return num;
705145516Sdarrenr}
706145516Sdarrenr
707145516Sdarrenr
708145516Sdarrenr/* ------------------------------------------------------------------------ */
709145516Sdarrenr/* Function:    ip_pool_free                                                */
710145516Sdarrenr/* Returns:     void                                                        */
711145516Sdarrenr/* Parameters:  ipo(I) -  pointer to pool structure                         */
712145516Sdarrenr/* Locks:       WRITE(ip_poolrw) or WRITE(ipf_global)                       */
713145516Sdarrenr/*                                                                          */
714145516Sdarrenr/* Deletes the pool strucutre passed in from the list of pools and deletes  */
715145516Sdarrenr/* all of the address information stored in it, including any tree data     */
716145516Sdarrenr/* structures also allocated.                                               */
717145516Sdarrenr/*                                                                          */
718170263Sdarrenr/* NOTE: Because this function is called out of ipfdetach() where ip_poolrw */
719145516Sdarrenr/* may not be initialised, we can't use an ASSERT to enforce the locking    */
720145516Sdarrenr/* assertion that one of the two (ip_poolrw,ipf_global) is held.            */
721145516Sdarrenr/* ------------------------------------------------------------------------ */
722145516Sdarrenrvoid ip_pool_free(ipo)
723145516Sdarrenrip_pool_t *ipo;
724145516Sdarrenr{
725170263Sdarrenr
726170263Sdarrenr	ip_pool_clearnodes(ipo);
727170263Sdarrenr
728170263Sdarrenr	if (ipo->ipo_next != NULL)
729170263Sdarrenr		ipo->ipo_next->ipo_pnext = ipo->ipo_pnext;
730170263Sdarrenr	*ipo->ipo_pnext = ipo->ipo_next;
731170263Sdarrenr	rn_freehead(ipo->ipo_head);
732170263Sdarrenr	KFREE(ipo);
733170263Sdarrenr
734170263Sdarrenr	ipoolstat.ipls_pools--;
735170263Sdarrenr}
736170263Sdarrenr
737170263Sdarrenr
738170263Sdarrenr/* ------------------------------------------------------------------------ */
739170263Sdarrenr/* Function:    ip_pool_clearnodes                                          */
740170263Sdarrenr/* Returns:     void                                                        */
741170263Sdarrenr/* Parameters:  ipo(I) -  pointer to pool structure                         */
742170263Sdarrenr/* Locks:       WRITE(ip_poolrw) or WRITE(ipf_global)                       */
743170263Sdarrenr/*                                                                          */
744170263Sdarrenr/* Deletes all nodes stored in a pool structure.                            */
745170263Sdarrenr/* ------------------------------------------------------------------------ */
746170263Sdarrenrstatic void ip_pool_clearnodes(ipo)
747170263Sdarrenrip_pool_t *ipo;
748170263Sdarrenr{
749145516Sdarrenr	ip_pool_node_t *n;
750145516Sdarrenr
751145516Sdarrenr	RADIX_NODE_HEAD_LOCK(ipo->ipo_head);
752145516Sdarrenr	while ((n = ipo->ipo_list) != NULL) {
753145516Sdarrenr		ipo->ipo_head->rnh_deladdr(&n->ipn_addr, &n->ipn_mask,
754145516Sdarrenr					   ipo->ipo_head);
755145516Sdarrenr
756145516Sdarrenr		*n->ipn_pnext = n->ipn_next;
757145516Sdarrenr		if (n->ipn_next)
758145516Sdarrenr			n->ipn_next->ipn_pnext = n->ipn_pnext;
759145516Sdarrenr
760145516Sdarrenr		KFREE(n);
761145516Sdarrenr
762145516Sdarrenr		ipoolstat.ipls_nodes--;
763145516Sdarrenr	}
764145516Sdarrenr	RADIX_NODE_HEAD_UNLOCK(ipo->ipo_head);
765145516Sdarrenr
766145516Sdarrenr	ipo->ipo_list = NULL;
767145516Sdarrenr}
768145516Sdarrenr
769145516Sdarrenr
770145516Sdarrenr/* ------------------------------------------------------------------------ */
771145516Sdarrenr/* Function:    ip_pool_deref                                               */
772145516Sdarrenr/* Returns:     void                                                        */
773145516Sdarrenr/* Parameters:  ipo(I) -  pointer to pool structure                         */
774145516Sdarrenr/* Locks:       WRITE(ip_poolrw)                                            */
775145516Sdarrenr/*                                                                          */
776145516Sdarrenr/* Drop the number of known references to this pool structure by one and if */
777145516Sdarrenr/* we arrive at zero known references, free it.                             */
778145516Sdarrenr/* ------------------------------------------------------------------------ */
779145516Sdarrenrvoid ip_pool_deref(ipo)
780145516Sdarrenrip_pool_t *ipo;
781145516Sdarrenr{
782145516Sdarrenr
783145516Sdarrenr	ipo->ipo_ref--;
784170263Sdarrenr
785145516Sdarrenr	if (ipo->ipo_ref == 0)
786145516Sdarrenr		ip_pool_free(ipo);
787170263Sdarrenr
788170263Sdarrenr	else if ((ipo->ipo_ref == 1) && (ipo->ipo_flags & IPOOL_DELETE))
789170263Sdarrenr		ip_pool_destroy(ipo->ipo_unit, ipo->ipo_name);
790145516Sdarrenr}
791145516Sdarrenr
792145516Sdarrenr
793170263Sdarrenr/* ------------------------------------------------------------------------ */
794170263Sdarrenr/* Function:    ip_pool_node_deref                                          */
795170263Sdarrenr/* Returns:     void                                                        */
796170263Sdarrenr/* Parameters:  ipn(I) - pointer to pool structure                          */
797170263Sdarrenr/* Locks:       WRITE(ip_poolrw)                                            */
798170263Sdarrenr/*                                                                          */
799170263Sdarrenr/* Drop a reference to the pool node passed in and if we're the last, free  */
800170263Sdarrenr/* it all up and adjust the stats accordingly.                              */
801170263Sdarrenr/* ------------------------------------------------------------------------ */
802170263Sdarrenrvoid ip_pool_node_deref(ipn)
803170263Sdarrenrip_pool_node_t *ipn;
804170263Sdarrenr{
805170263Sdarrenr
806170263Sdarrenr	ipn->ipn_ref--;
807170263Sdarrenr
808170263Sdarrenr	if (ipn->ipn_ref == 0) {
809170263Sdarrenr		KFREE(ipn);
810170263Sdarrenr		ipoolstat.ipls_nodes--;
811170263Sdarrenr	}
812170263Sdarrenr}
813170263Sdarrenr
814170263Sdarrenr
815170263Sdarrenr/* ------------------------------------------------------------------------ */
816170263Sdarrenr/* Function:    ip_pool_getnext                                             */
817170263Sdarrenr/* Returns:     void                                                        */
818170263Sdarrenr/* Parameters:  token(I) - pointer to pool structure                        */
819170263Sdarrenr/* Parameters:  ilp(IO)   - pointer to pool iterating structure             */
820170263Sdarrenr/*                                                                          */
821170263Sdarrenr/* ------------------------------------------------------------------------ */
822170263Sdarrenrint ip_pool_getnext(token, ilp)
823170263Sdarrenripftoken_t *token;
824170263Sdarrenripflookupiter_t *ilp;
825170263Sdarrenr{
826170263Sdarrenr	ip_pool_node_t *node, zn, *nextnode;
827170263Sdarrenr	ip_pool_t *ipo, zp, *nextipo;
828170263Sdarrenr	int err;
829170263Sdarrenr
830170263Sdarrenr	err = 0;
831170263Sdarrenr	node = NULL;
832170263Sdarrenr	nextnode = NULL;
833170263Sdarrenr	ipo = NULL;
834170263Sdarrenr	nextipo = NULL;
835170263Sdarrenr
836170263Sdarrenr	READ_ENTER(&ip_poolrw);
837170263Sdarrenr
838170263Sdarrenr	switch (ilp->ili_otype)
839170263Sdarrenr	{
840170263Sdarrenr	case IPFLOOKUPITER_LIST :
841170263Sdarrenr		ipo = token->ipt_data;
842170263Sdarrenr		if (ipo == NULL) {
843170263Sdarrenr			nextipo = ip_pool_list[(int)ilp->ili_unit];
844170263Sdarrenr		} else {
845170263Sdarrenr			nextipo = ipo->ipo_next;
846170263Sdarrenr		}
847170263Sdarrenr
848170263Sdarrenr		if (nextipo != NULL) {
849170263Sdarrenr			ATOMIC_INC(nextipo->ipo_ref);
850172771Sdarrenr			token->ipt_data = nextipo;
851170263Sdarrenr		} else {
852170263Sdarrenr			bzero((char *)&zp, sizeof(zp));
853170263Sdarrenr			nextipo = &zp;
854172771Sdarrenr			token->ipt_data = NULL;
855170263Sdarrenr		}
856170263Sdarrenr		break;
857170263Sdarrenr
858170263Sdarrenr	case IPFLOOKUPITER_NODE :
859170263Sdarrenr		node = token->ipt_data;
860170263Sdarrenr		if (node == NULL) {
861170263Sdarrenr			ipo = ip_pool_exists(ilp->ili_unit, ilp->ili_name);
862170263Sdarrenr			if (ipo == NULL)
863170263Sdarrenr				err = ESRCH;
864170263Sdarrenr			else {
865170263Sdarrenr				nextnode = ipo->ipo_list;
866170263Sdarrenr				ipo = NULL;
867170263Sdarrenr			}
868170263Sdarrenr		} else {
869170263Sdarrenr			nextnode = node->ipn_next;
870170263Sdarrenr		}
871170263Sdarrenr
872170263Sdarrenr		if (nextnode != NULL) {
873170263Sdarrenr			ATOMIC_INC(nextnode->ipn_ref);
874172771Sdarrenr			token->ipt_data = nextnode;
875170263Sdarrenr		} else {
876170263Sdarrenr			bzero((char *)&zn, sizeof(zn));
877170263Sdarrenr			nextnode = &zn;
878172771Sdarrenr			token->ipt_data = NULL;
879170263Sdarrenr		}
880170263Sdarrenr		break;
881170263Sdarrenr	default :
882170263Sdarrenr		err = EINVAL;
883170263Sdarrenr		break;
884170263Sdarrenr	}
885170263Sdarrenr
886170263Sdarrenr	RWLOCK_EXIT(&ip_poolrw);
887170263Sdarrenr
888170263Sdarrenr	if (err != 0)
889170263Sdarrenr		return err;
890170263Sdarrenr
891170263Sdarrenr	switch (ilp->ili_otype)
892170263Sdarrenr	{
893170263Sdarrenr	case IPFLOOKUPITER_LIST :
894170263Sdarrenr		if (ipo != NULL) {
895170263Sdarrenr			WRITE_ENTER(&ip_poolrw);
896170263Sdarrenr			ip_pool_deref(ipo);
897170263Sdarrenr			RWLOCK_EXIT(&ip_poolrw);
898170263Sdarrenr		}
899170263Sdarrenr		err = COPYOUT(nextipo, ilp->ili_data, sizeof(*nextipo));
900170263Sdarrenr		if (err != 0)
901170263Sdarrenr			err = EFAULT;
902170263Sdarrenr		break;
903170263Sdarrenr
904170263Sdarrenr	case IPFLOOKUPITER_NODE :
905170263Sdarrenr		if (node != NULL) {
906170263Sdarrenr			WRITE_ENTER(&ip_poolrw);
907170263Sdarrenr			ip_pool_node_deref(node);
908170263Sdarrenr			RWLOCK_EXIT(&ip_poolrw);
909170263Sdarrenr		}
910170263Sdarrenr		err = COPYOUT(nextnode, ilp->ili_data, sizeof(*nextnode));
911170263Sdarrenr		if (err != 0)
912170263Sdarrenr			err = EFAULT;
913170263Sdarrenr		break;
914170263Sdarrenr	}
915170263Sdarrenr
916170263Sdarrenr	return err;
917170263Sdarrenr}
918170263Sdarrenr
919170263Sdarrenr
920170263Sdarrenr/* ------------------------------------------------------------------------ */
921170263Sdarrenr/* Function:    ip_pool_iterderef                                           */
922170263Sdarrenr/* Returns:     void                                                        */
923170263Sdarrenr/* Parameters:  ipn(I) - pointer to pool structure                          */
924170263Sdarrenr/* Locks:       WRITE(ip_poolrw)                                            */
925170263Sdarrenr/*                                                                          */
926170263Sdarrenr/* ------------------------------------------------------------------------ */
927170263Sdarrenrvoid ip_pool_iterderef(otype, unit, data)
928170263Sdarrenru_int otype;
929170263Sdarrenrint unit;
930170263Sdarrenrvoid *data;
931170263Sdarrenr{
932170263Sdarrenr
933170263Sdarrenr	if (data == NULL)
934170263Sdarrenr		return;
935170263Sdarrenr
936170263Sdarrenr	if (unit < 0 || unit > IPL_LOGMAX)
937170263Sdarrenr		return;
938170263Sdarrenr
939170263Sdarrenr	switch (otype)
940170263Sdarrenr	{
941170263Sdarrenr	case IPFLOOKUPITER_LIST :
942170263Sdarrenr		WRITE_ENTER(&ip_poolrw);
943170263Sdarrenr		ip_pool_deref((ip_pool_t *)data);
944170263Sdarrenr		RWLOCK_EXIT(&ip_poolrw);
945170263Sdarrenr		break;
946170263Sdarrenr
947170263Sdarrenr	case IPFLOOKUPITER_NODE :
948170263Sdarrenr		WRITE_ENTER(&ip_poolrw);
949170263Sdarrenr		ip_pool_node_deref((ip_pool_node_t *)data);
950170263Sdarrenr		RWLOCK_EXIT(&ip_poolrw);
951170263Sdarrenr		break;
952170263Sdarrenr	default :
953170263Sdarrenr		break;
954170263Sdarrenr	}
955170263Sdarrenr}
956170263Sdarrenr
957170263Sdarrenr
958145516Sdarrenr# if defined(_KERNEL) && ((BSD >= 198911) && !defined(__osf__) && \
959145516Sdarrenr      !defined(__hpux) && !defined(__sgi))
960145516Sdarrenrstatic int
961145516Sdarrenrrn_freenode(struct radix_node *n, void *p)
962145516Sdarrenr{
963145516Sdarrenr	struct radix_node_head *rnh = p;
964145516Sdarrenr	struct radix_node *d;
965145516Sdarrenr
966145516Sdarrenr	d = rnh->rnh_deladdr(n->rn_key, NULL, rnh);
967145516Sdarrenr	if (d != NULL) {
968145516Sdarrenr		FreeS(d, max_keylen + 2 * sizeof (*d));
969145516Sdarrenr	}
970145516Sdarrenr	return 0;
971145516Sdarrenr}
972145516Sdarrenr
973145516Sdarrenr
974145516Sdarrenrvoid
975145516Sdarrenrrn_freehead(rnh)
976145516Sdarrenr      struct radix_node_head *rnh;
977145516Sdarrenr{
978145516Sdarrenr
979145516Sdarrenr	RADIX_NODE_HEAD_LOCK(rnh);
980145516Sdarrenr	(*rnh->rnh_walktree)(rnh, rn_freenode, rnh);
981145516Sdarrenr
982145516Sdarrenr	rnh->rnh_addaddr = NULL;
983145516Sdarrenr	rnh->rnh_deladdr = NULL;
984145516Sdarrenr	rnh->rnh_matchaddr = NULL;
985145516Sdarrenr	rnh->rnh_lookup = NULL;
986145516Sdarrenr	rnh->rnh_walktree = NULL;
987145516Sdarrenr	RADIX_NODE_HEAD_UNLOCK(rnh);
988145516Sdarrenr
989145516Sdarrenr	Free(rnh);
990145516Sdarrenr}
991145516Sdarrenr# endif
992145516Sdarrenr#endif /* IPFILTER_LOOKUP */
993