ip_pool.c revision 170263
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
56153872Sguido#if defined(_KERNEL) && (defined(__osf__) || defined(AIX) || \
57153872Sguido     defined(__hpux) || defined(__sgi))
58145516Sdarrenr# include "radix_ipf_local.h"
59145516Sdarrenr# define _RADIX_H_
60145516Sdarrenr#endif
61145516Sdarrenr#include <net/if.h>
62145516Sdarrenr#include <netinet/in.h>
63145516Sdarrenr
64145516Sdarrenr#include "netinet/ip_compat.h"
65145516Sdarrenr#include "netinet/ip_fil.h"
66145516Sdarrenr#include "netinet/ip_pool.h"
67145516Sdarrenr
68145516Sdarrenr#if defined(IPFILTER_LOOKUP) && defined(_KERNEL) && \
69145516Sdarrenr      ((BSD >= 198911) && !defined(__osf__) && \
70145516Sdarrenr      !defined(__hpux) && !defined(__sgi))
71145516Sdarrenrstatic int rn_freenode __P((struct radix_node *, void *));
72145516Sdarrenr#endif
73145516Sdarrenr
74145516Sdarrenr/* END OF INCLUDES */
75145516Sdarrenr
76145516Sdarrenr#if !defined(lint)
77145516Sdarrenrstatic const char sccsid[] = "@(#)ip_fil.c	2.41 6/5/96 (C) 1993-2000 Darren Reed";
78170263Sdarrenrstatic const char rcsid[] = "@(#)$Id: ip_pool.c,v 2.55.2.20 2007/05/31 12:27:35 darrenr Exp $";
79145516Sdarrenr#endif
80145516Sdarrenr
81145516Sdarrenr#ifdef IPFILTER_LOOKUP
82145516Sdarrenr
83145516Sdarrenr# ifndef RADIX_NODE_HEAD_LOCK
84145516Sdarrenr#  define RADIX_NODE_HEAD_LOCK(x)	;
85145516Sdarrenr# endif
86145516Sdarrenr# ifndef RADIX_NODE_HEAD_UNLOCK
87145516Sdarrenr#  define RADIX_NODE_HEAD_UNLOCK(x)	;
88145516Sdarrenr# endif
89145516Sdarrenr
90170263Sdarrenrstatic void ip_pool_clearnodes __P((ip_pool_t *));
91170263Sdarrenrstatic void *ip_pool_exists __P((int, char *));
92170263Sdarrenr
93145516Sdarrenrip_pool_stat_t ipoolstat;
94145516Sdarrenripfrwlock_t ip_poolrw;
95145516Sdarrenr
96145516Sdarrenr/*
97145516Sdarrenr * Binary tree routines from Sedgewick and enhanced to do ranges of addresses.
98145516Sdarrenr * NOTE: Insertion *MUST* be from greatest range to least for it to work!
99145516Sdarrenr * These should be replaced, eventually, by something else - most notably a
100145516Sdarrenr * interval searching method.  The important feature is to be able to find
101145516Sdarrenr * the best match.
102145516Sdarrenr *
103145516Sdarrenr * So why not use a radix tree for this?  As the first line implies, it
104145516Sdarrenr * has been written to work with a _range_ of addresses.  A range is not
105145516Sdarrenr * necessarily a match with any given netmask so what we end up dealing
106145516Sdarrenr * with is an interval tree.  Implementations of these are hard to find
107145516Sdarrenr * and the one herein is far from bug free.
108145516Sdarrenr *
109145516Sdarrenr * Sigh, in the end I became convinced that the bugs the code contained did
110145516Sdarrenr * not make it worthwhile not using radix trees.  For now the radix tree from
111145516Sdarrenr * 4.4 BSD is used, but this is not viewed as a long term solution.
112145516Sdarrenr */
113145516Sdarrenrip_pool_t *ip_pool_list[IPL_LOGSIZE] = { NULL, NULL, NULL, NULL,
114145516Sdarrenr					 NULL, NULL, NULL, NULL };
115145516Sdarrenr
116145516Sdarrenr
117145516Sdarrenr#ifdef TEST_POOL
118145516Sdarrenrvoid treeprint __P((ip_pool_t *));
119145516Sdarrenr
120145516Sdarrenrint
121145516Sdarrenrmain(argc, argv)
122145516Sdarrenr	int argc;
123145516Sdarrenr	char *argv[];
124145516Sdarrenr{
125145516Sdarrenr	addrfamily_t a, b;
126145516Sdarrenr	iplookupop_t op;
127145516Sdarrenr	ip_pool_t *ipo;
128145516Sdarrenr	i6addr_t ip;
129145516Sdarrenr
130145516Sdarrenr	RWLOCK_INIT(&ip_poolrw, "poolrw");
131145516Sdarrenr	ip_pool_init();
132145516Sdarrenr
133145516Sdarrenr	bzero((char *)&a, sizeof(a));
134145516Sdarrenr	bzero((char *)&b, sizeof(b));
135145516Sdarrenr	bzero((char *)&ip, sizeof(ip));
136145516Sdarrenr	bzero((char *)&op, sizeof(op));
137145516Sdarrenr	strcpy(op.iplo_name, "0");
138145516Sdarrenr
139145516Sdarrenr	if (ip_pool_create(&op) == 0)
140170263Sdarrenr		ipo = ip_pool_exists(0, "0");
141145516Sdarrenr
142145516Sdarrenr	a.adf_addr.in4.s_addr = 0x0a010203;
143145516Sdarrenr	b.adf_addr.in4.s_addr = 0xffffffff;
144145516Sdarrenr	ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 1);
145145516Sdarrenr	ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 1);
146145516Sdarrenr
147145516Sdarrenr	a.adf_addr.in4.s_addr = 0x0a000000;
148145516Sdarrenr	b.adf_addr.in4.s_addr = 0xff000000;
149145516Sdarrenr	ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 0);
150145516Sdarrenr	ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 0);
151145516Sdarrenr
152145516Sdarrenr	a.adf_addr.in4.s_addr = 0x0a010100;
153145516Sdarrenr	b.adf_addr.in4.s_addr = 0xffffff00;
154145516Sdarrenr	ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 1);
155145516Sdarrenr	ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 1);
156145516Sdarrenr
157145516Sdarrenr	a.adf_addr.in4.s_addr = 0x0a010200;
158145516Sdarrenr	b.adf_addr.in4.s_addr = 0xffffff00;
159145516Sdarrenr	ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 0);
160145516Sdarrenr	ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 0);
161145516Sdarrenr
162145516Sdarrenr	a.adf_addr.in4.s_addr = 0x0a010000;
163145516Sdarrenr	b.adf_addr.in4.s_addr = 0xffff0000;
164145516Sdarrenr	ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 1);
165145516Sdarrenr	ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 1);
166145516Sdarrenr
167145516Sdarrenr	a.adf_addr.in4.s_addr = 0x0a01020f;
168145516Sdarrenr	b.adf_addr.in4.s_addr = 0xffffffff;
169145516Sdarrenr	ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 1);
170145516Sdarrenr	ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 1);
171145516Sdarrenr#ifdef	DEBUG_POOL
172145516Sdarrenrtreeprint(ipo);
173145516Sdarrenr#endif
174145516Sdarrenr	ip.in4.s_addr = 0x0a00aabb;
175145516Sdarrenr	printf("search(%#x) = %d (0)\n", ip.in4.s_addr,
176145516Sdarrenr		ip_pool_search(ipo, 4, &ip));
177145516Sdarrenr
178145516Sdarrenr	ip.in4.s_addr = 0x0a000001;
179145516Sdarrenr	printf("search(%#x) = %d (0)\n", ip.in4.s_addr,
180145516Sdarrenr		ip_pool_search(ipo, 4, &ip));
181145516Sdarrenr
182145516Sdarrenr	ip.in4.s_addr = 0x0a000101;
183145516Sdarrenr	printf("search(%#x) = %d (0)\n", ip.in4.s_addr,
184145516Sdarrenr		ip_pool_search(ipo, 4, &ip));
185145516Sdarrenr
186145516Sdarrenr	ip.in4.s_addr = 0x0a010001;
187145516Sdarrenr	printf("search(%#x) = %d (1)\n", ip.in4.s_addr,
188145516Sdarrenr		ip_pool_search(ipo, 4, &ip));
189145516Sdarrenr
190145516Sdarrenr	ip.in4.s_addr = 0x0a010101;
191145516Sdarrenr	printf("search(%#x) = %d (1)\n", ip.in4.s_addr,
192145516Sdarrenr		ip_pool_search(ipo, 4, &ip));
193145516Sdarrenr
194145516Sdarrenr	ip.in4.s_addr = 0x0a010201;
195145516Sdarrenr	printf("search(%#x) = %d (0)\n", ip.in4.s_addr,
196145516Sdarrenr		ip_pool_search(ipo, 4, &ip));
197145516Sdarrenr
198145516Sdarrenr	ip.in4.s_addr = 0x0a010203;
199145516Sdarrenr	printf("search(%#x) = %d (1)\n", ip.in4.s_addr,
200145516Sdarrenr		ip_pool_search(ipo, 4, &ip));
201145516Sdarrenr
202145516Sdarrenr	ip.in4.s_addr = 0x0a01020f;
203145516Sdarrenr	printf("search(%#x) = %d (1)\n", ip.in4.s_addr,
204145516Sdarrenr		ip_pool_search(ipo, 4, &ip));
205145516Sdarrenr
206145516Sdarrenr	ip.in4.s_addr = 0x0b00aabb;
207145516Sdarrenr	printf("search(%#x) = %d (-1)\n", ip.in4.s_addr,
208145516Sdarrenr		ip_pool_search(ipo, 4, &ip));
209145516Sdarrenr
210145516Sdarrenr#ifdef	DEBUG_POOL
211145516Sdarrenrtreeprint(ipo);
212145516Sdarrenr#endif
213145516Sdarrenr
214145516Sdarrenr	ip_pool_fini();
215145516Sdarrenr
216145516Sdarrenr	return 0;
217145516Sdarrenr}
218145516Sdarrenr
219145516Sdarrenr
220145516Sdarrenrvoid
221145516Sdarrenrtreeprint(ipo)
222145516Sdarrenrip_pool_t *ipo;
223145516Sdarrenr{
224145516Sdarrenr	ip_pool_node_t *c;
225145516Sdarrenr
226145516Sdarrenr	for (c = ipo->ipo_list; c != NULL; c = c->ipn_next)
227145516Sdarrenr		printf("Node %p(%s) (%#x/%#x) = %d hits %lu\n",
228145516Sdarrenr			c, c->ipn_name, c->ipn_addr.adf_addr.in4.s_addr,
229145516Sdarrenr			c->ipn_mask.adf_addr.in4.s_addr,
230145516Sdarrenr			c->ipn_info, c->ipn_hits);
231145516Sdarrenr}
232145516Sdarrenr#endif /* TEST_POOL */
233145516Sdarrenr
234145516Sdarrenr
235145516Sdarrenr/* ------------------------------------------------------------------------ */
236145516Sdarrenr/* Function:    ip_pool_init                                                */
237145516Sdarrenr/* Returns:     int     - 0 = success, else error                           */
238145516Sdarrenr/*                                                                          */
239145516Sdarrenr/* Initialise the routing table data structures where required.             */
240145516Sdarrenr/* ------------------------------------------------------------------------ */
241145516Sdarrenrint ip_pool_init()
242145516Sdarrenr{
243145516Sdarrenr
244145516Sdarrenr	bzero((char *)&ipoolstat, sizeof(ipoolstat));
245145516Sdarrenr
246145516Sdarrenr#if (!defined(_KERNEL) || (BSD < 199306))
247145516Sdarrenr	rn_init();
248145516Sdarrenr#endif
249145516Sdarrenr	return 0;
250145516Sdarrenr}
251145516Sdarrenr
252145516Sdarrenr
253145516Sdarrenr/* ------------------------------------------------------------------------ */
254145516Sdarrenr/* Function:    ip_pool_fini                                                */
255145516Sdarrenr/* Returns:     int     - 0 = success, else error                           */
256145516Sdarrenr/* Locks:       WRITE(ipf_global)                                           */
257145516Sdarrenr/*                                                                          */
258145516Sdarrenr/* Clean up all the pool data structures allocated and call the cleanup     */
259145516Sdarrenr/* function for the radix tree that supports the pools. ip_pool_destroy() is*/
260145516Sdarrenr/* used to delete the pools one by one to ensure they're properly freed up. */
261145516Sdarrenr/* ------------------------------------------------------------------------ */
262145516Sdarrenrvoid ip_pool_fini()
263145516Sdarrenr{
264145516Sdarrenr	ip_pool_t *p, *q;
265145516Sdarrenr	int i;
266145516Sdarrenr
267145516Sdarrenr	ASSERT(rw_read_locked(&ipf_global.ipf_lk) == 0);
268145516Sdarrenr
269145516Sdarrenr	for (i = 0; i <= IPL_LOGMAX; i++) {
270145516Sdarrenr		for (q = ip_pool_list[i]; (p = q) != NULL; ) {
271145516Sdarrenr			q = p->ipo_next;
272170263Sdarrenr			(void) ip_pool_destroy(i, p->ipo_name);
273145516Sdarrenr		}
274145516Sdarrenr	}
275145516Sdarrenr
276145516Sdarrenr#if (!defined(_KERNEL) || (BSD < 199306))
277145516Sdarrenr	rn_fini();
278145516Sdarrenr#endif
279145516Sdarrenr}
280145516Sdarrenr
281145516Sdarrenr
282145516Sdarrenr/* ------------------------------------------------------------------------ */
283145516Sdarrenr/* Function:    ip_pool_statistics                                          */
284145516Sdarrenr/* Returns:     int     - 0 = success, else error                           */
285145516Sdarrenr/* Parameters:  op(I)   - pointer to lookup operation arguments             */
286145516Sdarrenr/*                                                                          */
287145516Sdarrenr/* Copy the current statistics out into user space, collecting pool list    */
288145516Sdarrenr/* pointers as appropriate for later use.                                   */
289145516Sdarrenr/* ------------------------------------------------------------------------ */
290145516Sdarrenrint ip_pool_statistics(op)
291145516Sdarrenriplookupop_t *op;
292145516Sdarrenr{
293145516Sdarrenr	ip_pool_stat_t stats;
294145516Sdarrenr	int unit, i, err = 0;
295145516Sdarrenr
296145516Sdarrenr	if (op->iplo_size != sizeof(ipoolstat))
297145516Sdarrenr		return EINVAL;
298145516Sdarrenr
299145516Sdarrenr	bcopy((char *)&ipoolstat, (char *)&stats, sizeof(stats));
300145516Sdarrenr	unit = op->iplo_unit;
301145516Sdarrenr	if (unit == IPL_LOGALL) {
302145516Sdarrenr		for (i = 0; i < IPL_LOGSIZE; i++)
303145516Sdarrenr			stats.ipls_list[i] = ip_pool_list[i];
304145516Sdarrenr	} else if (unit >= 0 && unit < IPL_LOGSIZE) {
305145516Sdarrenr		if (op->iplo_name[0] != '\0')
306170263Sdarrenr			stats.ipls_list[unit] = ip_pool_exists(unit,
307170263Sdarrenr							       op->iplo_name);
308145516Sdarrenr		else
309145516Sdarrenr			stats.ipls_list[unit] = ip_pool_list[unit];
310145516Sdarrenr	} else
311145516Sdarrenr		err = EINVAL;
312145516Sdarrenr	if (err == 0)
313145516Sdarrenr		err = COPYOUT(&stats, op->iplo_struct, sizeof(stats));
314145516Sdarrenr	return err;
315145516Sdarrenr}
316145516Sdarrenr
317145516Sdarrenr
318145516Sdarrenr/* ------------------------------------------------------------------------ */
319170263Sdarrenr/* Function:    ip_pool_exists                                              */
320145516Sdarrenr/* Returns:     int     - 0 = success, else error                           */
321145516Sdarrenr/* Parameters:  ipo(I)  - pointer to the pool getting the new node.         */
322145516Sdarrenr/*                                                                          */
323145516Sdarrenr/* Find a matching pool inside the collection of pools for a particular     */
324145516Sdarrenr/* device, indicated by the unit number.                                    */
325145516Sdarrenr/* ------------------------------------------------------------------------ */
326170263Sdarrenrstatic void *ip_pool_exists(unit, name)
327145516Sdarrenrint unit;
328145516Sdarrenrchar *name;
329145516Sdarrenr{
330145516Sdarrenr	ip_pool_t *p;
331145516Sdarrenr
332145516Sdarrenr	for (p = ip_pool_list[unit]; p != NULL; p = p->ipo_next)
333145516Sdarrenr		if (strncmp(p->ipo_name, name, sizeof(p->ipo_name)) == 0)
334145516Sdarrenr			break;
335145516Sdarrenr	return p;
336145516Sdarrenr}
337145516Sdarrenr
338145516Sdarrenr
339145516Sdarrenr/* ------------------------------------------------------------------------ */
340170263Sdarrenr/* Function:    ip_pool_find                                                */
341170263Sdarrenr/* Returns:     int     - 0 = success, else error                           */
342170263Sdarrenr/* Parameters:  ipo(I)  - pointer to the pool getting the new node.         */
343170263Sdarrenr/*                                                                          */
344170263Sdarrenr/* Find a matching pool inside the collection of pools for a particular     */
345170263Sdarrenr/* device, indicated by the unit number.  If it is marked for deletion then */
346170263Sdarrenr/* pretend it does not exist.                                               */
347170263Sdarrenr/* ------------------------------------------------------------------------ */
348170263Sdarrenrvoid *ip_pool_find(unit, name)
349170263Sdarrenrint unit;
350170263Sdarrenrchar *name;
351170263Sdarrenr{
352170263Sdarrenr	ip_pool_t *p;
353170263Sdarrenr
354170263Sdarrenr	p = ip_pool_exists(unit, name);
355170263Sdarrenr	if ((p != NULL) && (p->ipo_flags & IPOOL_DELETE))
356170263Sdarrenr		return NULL;
357170263Sdarrenr
358170263Sdarrenr	return p;
359170263Sdarrenr}
360170263Sdarrenr
361170263Sdarrenr
362170263Sdarrenr/* ------------------------------------------------------------------------ */
363145516Sdarrenr/* Function:    ip_pool_findeq                                              */
364145516Sdarrenr/* Returns:     int     - 0 = success, else error                           */
365145516Sdarrenr/* Parameters:  ipo(I)  - pointer to the pool getting the new node.         */
366145516Sdarrenr/*              addr(I) - pointer to address information to delete          */
367145516Sdarrenr/*              mask(I) -                                                   */
368145516Sdarrenr/*                                                                          */
369145516Sdarrenr/* Searches for an exact match of an entry in the pool.                     */
370145516Sdarrenr/* ------------------------------------------------------------------------ */
371145516Sdarrenrip_pool_node_t *ip_pool_findeq(ipo, addr, mask)
372145516Sdarrenrip_pool_t *ipo;
373145516Sdarrenraddrfamily_t *addr, *mask;
374145516Sdarrenr{
375145516Sdarrenr	struct radix_node *n;
376153872Sguido	SPL_INT(s);
377145516Sdarrenr
378145516Sdarrenr	SPL_NET(s);
379145516Sdarrenr	RADIX_NODE_HEAD_LOCK(ipo->ipo_head);
380145516Sdarrenr	n = ipo->ipo_head->rnh_lookup(addr, mask, ipo->ipo_head);
381145516Sdarrenr	RADIX_NODE_HEAD_UNLOCK(ipo->ipo_head);
382145516Sdarrenr	SPL_X(s);
383145516Sdarrenr	return (ip_pool_node_t *)n;
384145516Sdarrenr}
385145516Sdarrenr
386145516Sdarrenr
387145516Sdarrenr/* ------------------------------------------------------------------------ */
388145516Sdarrenr/* Function:    ip_pool_search                                              */
389145516Sdarrenr/* Returns:     int     - 0 == +ve match, -1 == error, 1 == -ve/no match    */
390145516Sdarrenr/* Parameters:  tptr(I)    - pointer to the pool to search                  */
391145516Sdarrenr/*              version(I) - IP protocol version (4 or 6)                   */
392145516Sdarrenr/*              dptr(I)    - pointer to address information                 */
393145516Sdarrenr/*                                                                          */
394145516Sdarrenr/* Search the pool for a given address and return a search result.          */
395145516Sdarrenr/* ------------------------------------------------------------------------ */
396170263Sdarrenrint ip_pool_search(tptr, ipversion, dptr)
397145516Sdarrenrvoid *tptr;
398170263Sdarrenrint ipversion;
399145516Sdarrenrvoid *dptr;
400145516Sdarrenr{
401145516Sdarrenr	struct radix_node *rn;
402145516Sdarrenr	ip_pool_node_t *m;
403145516Sdarrenr	i6addr_t *addr;
404145516Sdarrenr	addrfamily_t v;
405145516Sdarrenr	ip_pool_t *ipo;
406145516Sdarrenr	int rv;
407145516Sdarrenr
408145516Sdarrenr	ipo = tptr;
409145516Sdarrenr	if (ipo == NULL)
410145516Sdarrenr		return -1;
411145516Sdarrenr
412145516Sdarrenr	rv = 1;
413145516Sdarrenr	m = NULL;
414145516Sdarrenr	addr = (i6addr_t *)dptr;
415145516Sdarrenr	bzero(&v, sizeof(v));
416145516Sdarrenr	v.adf_len = offsetof(addrfamily_t, adf_addr);
417145516Sdarrenr
418170263Sdarrenr	if (ipversion == 4) {
419145516Sdarrenr		v.adf_len += sizeof(addr->in4);
420145516Sdarrenr		v.adf_addr.in4 = addr->in4;
421145516Sdarrenr#ifdef USE_INET6
422170263Sdarrenr	} else if (ipversion == 6) {
423145516Sdarrenr		v.adf_len += sizeof(addr->in6);
424145516Sdarrenr		v.adf_addr.in6 = addr->in6;
425145516Sdarrenr#endif
426145516Sdarrenr	} else
427145516Sdarrenr		return -1;
428145516Sdarrenr
429145516Sdarrenr	READ_ENTER(&ip_poolrw);
430145516Sdarrenr
431145516Sdarrenr	RADIX_NODE_HEAD_LOCK(ipo->ipo_head);
432145516Sdarrenr	rn = ipo->ipo_head->rnh_matchaddr(&v, ipo->ipo_head);
433145516Sdarrenr	RADIX_NODE_HEAD_UNLOCK(ipo->ipo_head);
434145516Sdarrenr
435145516Sdarrenr	if ((rn != NULL) && ((rn->rn_flags & RNF_ROOT) == 0)) {
436145516Sdarrenr		m = (ip_pool_node_t *)rn;
437145516Sdarrenr		ipo->ipo_hits++;
438145516Sdarrenr		m->ipn_hits++;
439145516Sdarrenr		rv = m->ipn_info;
440145516Sdarrenr	}
441145516Sdarrenr	RWLOCK_EXIT(&ip_poolrw);
442145516Sdarrenr	return rv;
443145516Sdarrenr}
444145516Sdarrenr
445145516Sdarrenr
446145516Sdarrenr/* ------------------------------------------------------------------------ */
447145516Sdarrenr/* Function:    ip_pool_insert                                              */
448145516Sdarrenr/* Returns:     int     - 0 = success, else error                           */
449145516Sdarrenr/* Parameters:  ipo(I)  - pointer to the pool getting the new node.         */
450145516Sdarrenr/*              addr(I) - address being added as a node                     */
451145516Sdarrenr/*              mask(I) - netmask to with the node being added              */
452145516Sdarrenr/*              info(I) - extra information to store in this node.          */
453145516Sdarrenr/* Locks:       WRITE(ip_poolrw)                                            */
454145516Sdarrenr/*                                                                          */
455145516Sdarrenr/* Add another node to the pool given by ipo.  The three parameters passed  */
456145516Sdarrenr/* in (addr, mask, info) shold all be stored in the node.                   */
457145516Sdarrenr/* ------------------------------------------------------------------------ */
458145516Sdarrenrint ip_pool_insert(ipo, addr, mask, info)
459145516Sdarrenrip_pool_t *ipo;
460145516Sdarrenri6addr_t *addr, *mask;
461145516Sdarrenrint info;
462145516Sdarrenr{
463145516Sdarrenr	struct radix_node *rn;
464145516Sdarrenr	ip_pool_node_t *x;
465145516Sdarrenr
466145516Sdarrenr	ASSERT(rw_read_locked(&ip_poolrw.ipf_lk) == 0);
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
532145516Sdarrenr	ASSERT(rw_read_locked(&ip_poolrw.ipf_lk) == 0);
533145516Sdarrenr
534170263Sdarrenr	unit = op->iplo_unit;
535145516Sdarrenr
536170263Sdarrenr	if ((op->iplo_arg & LOOKUP_ANON) == 0)
537170263Sdarrenr		h = ip_pool_exists(unit, op->iplo_name);
538170263Sdarrenr	else
539170263Sdarrenr		h = NULL;
540170263Sdarrenr
541170263Sdarrenr	if (h != NULL) {
542170263Sdarrenr		if ((h->ipo_flags & IPOOL_DELETE) != 0) {
543170263Sdarrenr			h->ipo_flags &= ~IPOOL_DELETE;
544170263Sdarrenr			return 0;
545170263Sdarrenr		}
546170263Sdarrenr		return EEXIST;
547170263Sdarrenr	} else {
548170263Sdarrenr		KMALLOC(h, ip_pool_t *);
549170263Sdarrenr		if (h == NULL)
550170263Sdarrenr			return ENOMEM;
551170263Sdarrenr		bzero(h, sizeof(*h));
552170263Sdarrenr
553170263Sdarrenr		if (rn_inithead((void **)&h->ipo_head,
554170263Sdarrenr				offsetof(addrfamily_t, adf_addr) << 3) == 0) {
555170263Sdarrenr			KFREE(h);
556170263Sdarrenr			return ENOMEM;
557170263Sdarrenr		}
558145516Sdarrenr	}
559145516Sdarrenr
560170263Sdarrenr	if ((op->iplo_arg & LOOKUP_ANON) != 0) {
561145516Sdarrenr		ip_pool_t *p;
562145516Sdarrenr
563170263Sdarrenr		h->ipo_flags |= IPOOL_ANON;
564170263Sdarrenr		poolnum = LOOKUP_ANON;
565145516Sdarrenr
566145516Sdarrenr#if defined(SNPRINTF) && defined(_KERNEL)
567145516Sdarrenr		SNPRINTF(name, sizeof(name), "%x", poolnum);
568145516Sdarrenr#else
569145516Sdarrenr		(void)sprintf(name, "%x", poolnum);
570145516Sdarrenr#endif
571145516Sdarrenr
572145516Sdarrenr		for (p = ip_pool_list[unit]; p != NULL; ) {
573145516Sdarrenr			if (strncmp(name, p->ipo_name,
574145516Sdarrenr				    sizeof(p->ipo_name)) == 0) {
575145516Sdarrenr				poolnum++;
576145516Sdarrenr#if defined(SNPRINTF) && defined(_KERNEL)
577145516Sdarrenr				SNPRINTF(name, sizeof(name), "%x", poolnum);
578145516Sdarrenr#else
579145516Sdarrenr				(void)sprintf(name, "%x", poolnum);
580145516Sdarrenr#endif
581145516Sdarrenr				p = ip_pool_list[unit];
582145516Sdarrenr			} else
583145516Sdarrenr				p = p->ipo_next;
584145516Sdarrenr		}
585145516Sdarrenr
586145516Sdarrenr		(void)strncpy(h->ipo_name, name, sizeof(h->ipo_name));
587153872Sguido		(void)strncpy(op->iplo_name, name, sizeof(op->iplo_name));
588145516Sdarrenr	} else {
589170263Sdarrenr		(void)strncpy(h->ipo_name, op->iplo_name, sizeof(h->ipo_name));
590145516Sdarrenr	}
591145516Sdarrenr
592170263Sdarrenr	if ((h->ipo_flags & IPOOL_DELETE) == 0) {
593170263Sdarrenr		h->ipo_ref = 1;
594170263Sdarrenr		h->ipo_list = NULL;
595170263Sdarrenr		h->ipo_unit = unit;
596170263Sdarrenr		h->ipo_next = ip_pool_list[unit];
597170263Sdarrenr		if (ip_pool_list[unit] != NULL)
598170263Sdarrenr			ip_pool_list[unit]->ipo_pnext = &h->ipo_next;
599170263Sdarrenr		h->ipo_pnext = &ip_pool_list[unit];
600170263Sdarrenr		ip_pool_list[unit] = h;
601145516Sdarrenr
602170263Sdarrenr		ipoolstat.ipls_pools++;
603170263Sdarrenr	}
604145516Sdarrenr
605145516Sdarrenr	return 0;
606145516Sdarrenr}
607145516Sdarrenr
608145516Sdarrenr
609145516Sdarrenr/* ------------------------------------------------------------------------ */
610145516Sdarrenr/* Function:    ip_pool_remove                                              */
611145516Sdarrenr/* Returns:     int    - 0 = success, else error                            */
612145516Sdarrenr/* Parameters:  ipo(I) - pointer to the pool to remove the node from.       */
613145516Sdarrenr/*              ipe(I) - address being deleted as a node                    */
614145516Sdarrenr/* Locks:       WRITE(ip_poolrw)                                            */
615145516Sdarrenr/*                                                                          */
616170263Sdarrenr/* Remove a node from the pool given by ipo.                                */
617145516Sdarrenr/* ------------------------------------------------------------------------ */
618145516Sdarrenrint ip_pool_remove(ipo, ipe)
619145516Sdarrenrip_pool_t *ipo;
620145516Sdarrenrip_pool_node_t *ipe;
621145516Sdarrenr{
622145516Sdarrenr
623145516Sdarrenr	ASSERT(rw_read_locked(&ip_poolrw.ipf_lk) == 0);
624145516Sdarrenr
625170263Sdarrenr	if (ipe->ipn_pnext != NULL)
626170263Sdarrenr		*ipe->ipn_pnext = ipe->ipn_next;
627170263Sdarrenr	if (ipe->ipn_next != NULL)
628170263Sdarrenr		ipe->ipn_next->ipn_pnext = ipe->ipn_pnext;
629145516Sdarrenr
630145516Sdarrenr	RADIX_NODE_HEAD_LOCK(ipo->ipo_head);
631170263Sdarrenr	ipo->ipo_head->rnh_deladdr(&ipe->ipn_addr, &ipe->ipn_mask,
632145516Sdarrenr				   ipo->ipo_head);
633145516Sdarrenr	RADIX_NODE_HEAD_UNLOCK(ipo->ipo_head);
634145516Sdarrenr
635170263Sdarrenr	ip_pool_node_deref(ipe);
636145516Sdarrenr
637145516Sdarrenr	return 0;
638145516Sdarrenr}
639145516Sdarrenr
640145516Sdarrenr
641145516Sdarrenr/* ------------------------------------------------------------------------ */
642145516Sdarrenr/* Function:    ip_pool_destroy                                             */
643145516Sdarrenr/* Returns:     int    - 0 = success, else error                            */
644145516Sdarrenr/* Parameters:  op(I)  -  information about the pool to remove              */
645145516Sdarrenr/* Locks:       WRITE(ip_poolrw) or WRITE(ipf_global)                       */
646145516Sdarrenr/*                                                                          */
647145516Sdarrenr/* Search for a pool using paramters passed in and if it's not otherwise    */
648170263Sdarrenr/* busy, free it.  If it is busy, clear all of its nodes, mark it for being */
649170263Sdarrenr/* deleted and return an error saying it is busy.                           */
650145516Sdarrenr/*                                                                          */
651170263Sdarrenr/* NOTE: Because this function is called out of ipfdetach() where ip_poolrw */
652145516Sdarrenr/* may not be initialised, we can't use an ASSERT to enforce the locking    */
653145516Sdarrenr/* assertion that one of the two (ip_poolrw,ipf_global) is held.            */
654145516Sdarrenr/* ------------------------------------------------------------------------ */
655170263Sdarrenrint ip_pool_destroy(unit, name)
656170263Sdarrenrint unit;
657170263Sdarrenrchar *name;
658145516Sdarrenr{
659145516Sdarrenr	ip_pool_t *ipo;
660145516Sdarrenr
661170263Sdarrenr	ipo = ip_pool_exists(unit, name);
662145516Sdarrenr	if (ipo == NULL)
663145516Sdarrenr		return ESRCH;
664145516Sdarrenr
665170263Sdarrenr	if (ipo->ipo_ref != 1) {
666170263Sdarrenr		ip_pool_clearnodes(ipo);
667170263Sdarrenr		ipo->ipo_flags |= IPOOL_DELETE;
668170263Sdarrenr		return 0;
669170263Sdarrenr	}
670145516Sdarrenr
671145516Sdarrenr	ip_pool_free(ipo);
672145516Sdarrenr	return 0;
673145516Sdarrenr}
674145516Sdarrenr
675145516Sdarrenr
676145516Sdarrenr/* ------------------------------------------------------------------------ */
677145516Sdarrenr/* Function:    ip_pool_flush                                               */
678145516Sdarrenr/* Returns:     int    - number of pools deleted                            */
679145516Sdarrenr/* Parameters:  fp(I)  - which pool(s) to flush                             */
680145516Sdarrenr/* Locks:       WRITE(ip_poolrw) or WRITE(ipf_global)                       */
681145516Sdarrenr/*                                                                          */
682145516Sdarrenr/* Free all pools associated with the device that matches the unit number   */
683145516Sdarrenr/* passed in with operation.                                                */
684145516Sdarrenr/*                                                                          */
685170263Sdarrenr/* NOTE: Because this function is called out of ipfdetach() where ip_poolrw */
686145516Sdarrenr/* may not be initialised, we can't use an ASSERT to enforce the locking    */
687145516Sdarrenr/* assertion that one of the two (ip_poolrw,ipf_global) is held.            */
688145516Sdarrenr/* ------------------------------------------------------------------------ */
689145516Sdarrenrint ip_pool_flush(fp)
690145516Sdarrenriplookupflush_t *fp;
691145516Sdarrenr{
692145516Sdarrenr	int i, num = 0, unit, err;
693145516Sdarrenr	ip_pool_t *p, *q;
694145516Sdarrenr	iplookupop_t op;
695145516Sdarrenr
696145516Sdarrenr	unit = fp->iplf_unit;
697145516Sdarrenr
698145516Sdarrenr	for (i = 0; i <= IPL_LOGMAX; i++) {
699145516Sdarrenr		if (unit != IPLT_ALL && i != unit)
700145516Sdarrenr			continue;
701145516Sdarrenr		for (q = ip_pool_list[i]; (p = q) != NULL; ) {
702145516Sdarrenr			op.iplo_unit = i;
703145516Sdarrenr			(void)strncpy(op.iplo_name, p->ipo_name,
704145516Sdarrenr				sizeof(op.iplo_name));
705145516Sdarrenr			q = p->ipo_next;
706170263Sdarrenr			err = ip_pool_destroy(op.iplo_unit, op.iplo_name);
707145516Sdarrenr			if (err == 0)
708145516Sdarrenr				num++;
709145516Sdarrenr			else
710145516Sdarrenr				break;
711145516Sdarrenr		}
712145516Sdarrenr	}
713145516Sdarrenr	return num;
714145516Sdarrenr}
715145516Sdarrenr
716145516Sdarrenr
717145516Sdarrenr/* ------------------------------------------------------------------------ */
718145516Sdarrenr/* Function:    ip_pool_free                                                */
719145516Sdarrenr/* Returns:     void                                                        */
720145516Sdarrenr/* Parameters:  ipo(I) -  pointer to pool structure                         */
721145516Sdarrenr/* Locks:       WRITE(ip_poolrw) or WRITE(ipf_global)                       */
722145516Sdarrenr/*                                                                          */
723145516Sdarrenr/* Deletes the pool strucutre passed in from the list of pools and deletes  */
724145516Sdarrenr/* all of the address information stored in it, including any tree data     */
725145516Sdarrenr/* structures also allocated.                                               */
726145516Sdarrenr/*                                                                          */
727170263Sdarrenr/* NOTE: Because this function is called out of ipfdetach() where ip_poolrw */
728145516Sdarrenr/* may not be initialised, we can't use an ASSERT to enforce the locking    */
729145516Sdarrenr/* assertion that one of the two (ip_poolrw,ipf_global) is held.            */
730145516Sdarrenr/* ------------------------------------------------------------------------ */
731145516Sdarrenrvoid ip_pool_free(ipo)
732145516Sdarrenrip_pool_t *ipo;
733145516Sdarrenr{
734170263Sdarrenr
735170263Sdarrenr	ip_pool_clearnodes(ipo);
736170263Sdarrenr
737170263Sdarrenr	if (ipo->ipo_next != NULL)
738170263Sdarrenr		ipo->ipo_next->ipo_pnext = ipo->ipo_pnext;
739170263Sdarrenr	*ipo->ipo_pnext = ipo->ipo_next;
740170263Sdarrenr	rn_freehead(ipo->ipo_head);
741170263Sdarrenr	KFREE(ipo);
742170263Sdarrenr
743170263Sdarrenr	ipoolstat.ipls_pools--;
744170263Sdarrenr}
745170263Sdarrenr
746170263Sdarrenr
747170263Sdarrenr/* ------------------------------------------------------------------------ */
748170263Sdarrenr/* Function:    ip_pool_clearnodes                                          */
749170263Sdarrenr/* Returns:     void                                                        */
750170263Sdarrenr/* Parameters:  ipo(I) -  pointer to pool structure                         */
751170263Sdarrenr/* Locks:       WRITE(ip_poolrw) or WRITE(ipf_global)                       */
752170263Sdarrenr/*                                                                          */
753170263Sdarrenr/* Deletes all nodes stored in a pool structure.                            */
754170263Sdarrenr/* ------------------------------------------------------------------------ */
755170263Sdarrenrstatic void ip_pool_clearnodes(ipo)
756170263Sdarrenrip_pool_t *ipo;
757170263Sdarrenr{
758145516Sdarrenr	ip_pool_node_t *n;
759145516Sdarrenr
760145516Sdarrenr	RADIX_NODE_HEAD_LOCK(ipo->ipo_head);
761145516Sdarrenr	while ((n = ipo->ipo_list) != NULL) {
762145516Sdarrenr		ipo->ipo_head->rnh_deladdr(&n->ipn_addr, &n->ipn_mask,
763145516Sdarrenr					   ipo->ipo_head);
764145516Sdarrenr
765145516Sdarrenr		*n->ipn_pnext = n->ipn_next;
766145516Sdarrenr		if (n->ipn_next)
767145516Sdarrenr			n->ipn_next->ipn_pnext = n->ipn_pnext;
768145516Sdarrenr
769145516Sdarrenr		KFREE(n);
770145516Sdarrenr
771145516Sdarrenr		ipoolstat.ipls_nodes--;
772145516Sdarrenr	}
773145516Sdarrenr	RADIX_NODE_HEAD_UNLOCK(ipo->ipo_head);
774145516Sdarrenr
775145516Sdarrenr	ipo->ipo_list = NULL;
776145516Sdarrenr}
777145516Sdarrenr
778145516Sdarrenr
779145516Sdarrenr/* ------------------------------------------------------------------------ */
780145516Sdarrenr/* Function:    ip_pool_deref                                               */
781145516Sdarrenr/* Returns:     void                                                        */
782145516Sdarrenr/* Parameters:  ipo(I) -  pointer to pool structure                         */
783145516Sdarrenr/* Locks:       WRITE(ip_poolrw)                                            */
784145516Sdarrenr/*                                                                          */
785145516Sdarrenr/* Drop the number of known references to this pool structure by one and if */
786145516Sdarrenr/* we arrive at zero known references, free it.                             */
787145516Sdarrenr/* ------------------------------------------------------------------------ */
788145516Sdarrenrvoid ip_pool_deref(ipo)
789145516Sdarrenrip_pool_t *ipo;
790145516Sdarrenr{
791145516Sdarrenr
792145516Sdarrenr	ASSERT(rw_read_locked(&ip_poolrw.ipf_lk) == 0);
793145516Sdarrenr
794145516Sdarrenr	ipo->ipo_ref--;
795170263Sdarrenr
796145516Sdarrenr	if (ipo->ipo_ref == 0)
797145516Sdarrenr		ip_pool_free(ipo);
798170263Sdarrenr
799170263Sdarrenr	else if ((ipo->ipo_ref == 1) && (ipo->ipo_flags & IPOOL_DELETE))
800170263Sdarrenr		ip_pool_destroy(ipo->ipo_unit, ipo->ipo_name);
801145516Sdarrenr}
802145516Sdarrenr
803145516Sdarrenr
804170263Sdarrenr/* ------------------------------------------------------------------------ */
805170263Sdarrenr/* Function:    ip_pool_node_deref                                          */
806170263Sdarrenr/* Returns:     void                                                        */
807170263Sdarrenr/* Parameters:  ipn(I) - pointer to pool structure                          */
808170263Sdarrenr/* Locks:       WRITE(ip_poolrw)                                            */
809170263Sdarrenr/*                                                                          */
810170263Sdarrenr/* Drop a reference to the pool node passed in and if we're the last, free  */
811170263Sdarrenr/* it all up and adjust the stats accordingly.                              */
812170263Sdarrenr/* ------------------------------------------------------------------------ */
813170263Sdarrenrvoid ip_pool_node_deref(ipn)
814170263Sdarrenrip_pool_node_t *ipn;
815170263Sdarrenr{
816170263Sdarrenr
817170263Sdarrenr	ipn->ipn_ref--;
818170263Sdarrenr
819170263Sdarrenr	if (ipn->ipn_ref == 0) {
820170263Sdarrenr		KFREE(ipn);
821170263Sdarrenr		ipoolstat.ipls_nodes--;
822170263Sdarrenr	}
823170263Sdarrenr}
824170263Sdarrenr
825170263Sdarrenr
826170263Sdarrenr/* ------------------------------------------------------------------------ */
827170263Sdarrenr/* Function:    ip_pool_getnext                                             */
828170263Sdarrenr/* Returns:     void                                                        */
829170263Sdarrenr/* Parameters:  token(I) - pointer to pool structure                        */
830170263Sdarrenr/* Parameters:  ilp(IO)   - pointer to pool iterating structure             */
831170263Sdarrenr/*                                                                          */
832170263Sdarrenr/* ------------------------------------------------------------------------ */
833170263Sdarrenrint ip_pool_getnext(token, ilp)
834170263Sdarrenripftoken_t *token;
835170263Sdarrenripflookupiter_t *ilp;
836170263Sdarrenr{
837170263Sdarrenr	ip_pool_node_t *node, zn, *nextnode;
838170263Sdarrenr	ip_pool_t *ipo, zp, *nextipo;
839170263Sdarrenr	int err;
840170263Sdarrenr
841170263Sdarrenr	err = 0;
842170263Sdarrenr	node = NULL;
843170263Sdarrenr	nextnode = NULL;
844170263Sdarrenr	ipo = NULL;
845170263Sdarrenr	nextipo = NULL;
846170263Sdarrenr
847170263Sdarrenr	READ_ENTER(&ip_poolrw);
848170263Sdarrenr
849170263Sdarrenr	switch (ilp->ili_otype)
850170263Sdarrenr	{
851170263Sdarrenr	case IPFLOOKUPITER_LIST :
852170263Sdarrenr		ipo = token->ipt_data;
853170263Sdarrenr		if (ipo == NULL) {
854170263Sdarrenr			nextipo = ip_pool_list[(int)ilp->ili_unit];
855170263Sdarrenr		} else {
856170263Sdarrenr			nextipo = ipo->ipo_next;
857170263Sdarrenr		}
858170263Sdarrenr
859170263Sdarrenr		if (nextipo != NULL) {
860170263Sdarrenr			ATOMIC_INC(nextipo->ipo_ref);
861170263Sdarrenr			if (nextipo->ipo_next == NULL)
862170263Sdarrenr				token->ipt_alive = 0;
863170263Sdarrenr		} else {
864170263Sdarrenr			bzero((char *)&zp, sizeof(zp));
865170263Sdarrenr			nextipo = &zp;
866170263Sdarrenr		}
867170263Sdarrenr		break;
868170263Sdarrenr
869170263Sdarrenr	case IPFLOOKUPITER_NODE :
870170263Sdarrenr		node = token->ipt_data;
871170263Sdarrenr		if (node == NULL) {
872170263Sdarrenr			ipo = ip_pool_exists(ilp->ili_unit, ilp->ili_name);
873170263Sdarrenr			if (ipo == NULL)
874170263Sdarrenr				err = ESRCH;
875170263Sdarrenr			else {
876170263Sdarrenr				nextnode = ipo->ipo_list;
877170263Sdarrenr				ipo = NULL;
878170263Sdarrenr			}
879170263Sdarrenr		} else {
880170263Sdarrenr			nextnode = node->ipn_next;
881170263Sdarrenr		}
882170263Sdarrenr
883170263Sdarrenr		if (nextnode != NULL) {
884170263Sdarrenr			ATOMIC_INC(nextnode->ipn_ref);
885170263Sdarrenr			if (nextnode->ipn_next == NULL)
886170263Sdarrenr				token->ipt_alive = 0;
887170263Sdarrenr		} else {
888170263Sdarrenr			bzero((char *)&zn, sizeof(zn));
889170263Sdarrenr			nextnode = &zn;
890170263Sdarrenr		}
891170263Sdarrenr		break;
892170263Sdarrenr	default :
893170263Sdarrenr		err = EINVAL;
894170263Sdarrenr		break;
895170263Sdarrenr	}
896170263Sdarrenr
897170263Sdarrenr	RWLOCK_EXIT(&ip_poolrw);
898170263Sdarrenr
899170263Sdarrenr	if (err != 0)
900170263Sdarrenr		return err;
901170263Sdarrenr
902170263Sdarrenr	switch (ilp->ili_otype)
903170263Sdarrenr	{
904170263Sdarrenr	case IPFLOOKUPITER_LIST :
905170263Sdarrenr		if (ipo != NULL) {
906170263Sdarrenr			WRITE_ENTER(&ip_poolrw);
907170263Sdarrenr			ip_pool_deref(ipo);
908170263Sdarrenr			RWLOCK_EXIT(&ip_poolrw);
909170263Sdarrenr		}
910170263Sdarrenr		token->ipt_data = nextipo;
911170263Sdarrenr		err = COPYOUT(nextipo, ilp->ili_data, sizeof(*nextipo));
912170263Sdarrenr		if (err != 0)
913170263Sdarrenr			err = EFAULT;
914170263Sdarrenr		break;
915170263Sdarrenr
916170263Sdarrenr	case IPFLOOKUPITER_NODE :
917170263Sdarrenr		if (node != NULL) {
918170263Sdarrenr			WRITE_ENTER(&ip_poolrw);
919170263Sdarrenr			ip_pool_node_deref(node);
920170263Sdarrenr			RWLOCK_EXIT(&ip_poolrw);
921170263Sdarrenr		}
922170263Sdarrenr		token->ipt_data = nextnode;
923170263Sdarrenr		err = COPYOUT(nextnode, ilp->ili_data, sizeof(*nextnode));
924170263Sdarrenr		if (err != 0)
925170263Sdarrenr			err = EFAULT;
926170263Sdarrenr		break;
927170263Sdarrenr	}
928170263Sdarrenr
929170263Sdarrenr	return err;
930170263Sdarrenr}
931170263Sdarrenr
932170263Sdarrenr
933170263Sdarrenr/* ------------------------------------------------------------------------ */
934170263Sdarrenr/* Function:    ip_pool_iterderef                                           */
935170263Sdarrenr/* Returns:     void                                                        */
936170263Sdarrenr/* Parameters:  ipn(I) - pointer to pool structure                          */
937170263Sdarrenr/* Locks:       WRITE(ip_poolrw)                                            */
938170263Sdarrenr/*                                                                          */
939170263Sdarrenr/* ------------------------------------------------------------------------ */
940170263Sdarrenrvoid ip_pool_iterderef(otype, unit, data)
941170263Sdarrenru_int otype;
942170263Sdarrenrint unit;
943170263Sdarrenrvoid *data;
944170263Sdarrenr{
945170263Sdarrenr
946170263Sdarrenr	if (data == NULL)
947170263Sdarrenr		return;
948170263Sdarrenr
949170263Sdarrenr	if (unit < 0 || unit > IPL_LOGMAX)
950170263Sdarrenr		return;
951170263Sdarrenr
952170263Sdarrenr	switch (otype)
953170263Sdarrenr	{
954170263Sdarrenr	case IPFLOOKUPITER_LIST :
955170263Sdarrenr		WRITE_ENTER(&ip_poolrw);
956170263Sdarrenr		ip_pool_deref((ip_pool_t *)data);
957170263Sdarrenr		RWLOCK_EXIT(&ip_poolrw);
958170263Sdarrenr		break;
959170263Sdarrenr
960170263Sdarrenr	case IPFLOOKUPITER_NODE :
961170263Sdarrenr		WRITE_ENTER(&ip_poolrw);
962170263Sdarrenr		ip_pool_node_deref((ip_pool_node_t *)data);
963170263Sdarrenr		RWLOCK_EXIT(&ip_poolrw);
964170263Sdarrenr		break;
965170263Sdarrenr	default :
966170263Sdarrenr		break;
967170263Sdarrenr	}
968170263Sdarrenr}
969170263Sdarrenr
970170263Sdarrenr
971145516Sdarrenr# if defined(_KERNEL) && ((BSD >= 198911) && !defined(__osf__) && \
972145516Sdarrenr      !defined(__hpux) && !defined(__sgi))
973145516Sdarrenrstatic int
974145516Sdarrenrrn_freenode(struct radix_node *n, void *p)
975145516Sdarrenr{
976145516Sdarrenr	struct radix_node_head *rnh = p;
977145516Sdarrenr	struct radix_node *d;
978145516Sdarrenr
979145516Sdarrenr	d = rnh->rnh_deladdr(n->rn_key, NULL, rnh);
980145516Sdarrenr	if (d != NULL) {
981145516Sdarrenr		FreeS(d, max_keylen + 2 * sizeof (*d));
982145516Sdarrenr	}
983145516Sdarrenr	return 0;
984145516Sdarrenr}
985145516Sdarrenr
986145516Sdarrenr
987145516Sdarrenrvoid
988145516Sdarrenrrn_freehead(rnh)
989145516Sdarrenr      struct radix_node_head *rnh;
990145516Sdarrenr{
991145516Sdarrenr
992145516Sdarrenr	RADIX_NODE_HEAD_LOCK(rnh);
993145516Sdarrenr	(*rnh->rnh_walktree)(rnh, rn_freenode, rnh);
994145516Sdarrenr
995145516Sdarrenr	rnh->rnh_addaddr = NULL;
996145516Sdarrenr	rnh->rnh_deladdr = NULL;
997145516Sdarrenr	rnh->rnh_matchaddr = NULL;
998145516Sdarrenr	rnh->rnh_lookup = NULL;
999145516Sdarrenr	rnh->rnh_walktree = NULL;
1000145516Sdarrenr	RADIX_NODE_HEAD_UNLOCK(rnh);
1001145516Sdarrenr
1002145516Sdarrenr	Free(rnh);
1003145516Sdarrenr}
1004145516Sdarrenr# endif
1005145516Sdarrenr#endif /* IPFILTER_LOOKUP */
1006