ip_pool.c revision 153872
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# ifdef __osf__
59145516Sdarrenr#  include <net/radix.h>
60145516Sdarrenr# endif
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";
81153872Sguidostatic const char rcsid[] = "@(#)$Id: ip_pool.c,v 2.55.2.15 2005/11/13 15:38:37 darrenr Exp $";
82145516Sdarrenr#endif
83145516Sdarrenr
84145516Sdarrenr#ifdef IPFILTER_LOOKUP
85145516Sdarrenr
86145516Sdarrenr# ifndef RADIX_NODE_HEAD_LOCK
87145516Sdarrenr#  define RADIX_NODE_HEAD_LOCK(x)	;
88145516Sdarrenr# endif
89145516Sdarrenr# ifndef RADIX_NODE_HEAD_UNLOCK
90145516Sdarrenr#  define RADIX_NODE_HEAD_UNLOCK(x)	;
91145516Sdarrenr# endif
92145516Sdarrenr
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)
140145516Sdarrenr		ipo = ip_pool_find(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	iplookupop_t op;
266145516Sdarrenr	int i;
267145516Sdarrenr
268145516Sdarrenr	ASSERT(rw_read_locked(&ipf_global.ipf_lk) == 0);
269145516Sdarrenr
270145516Sdarrenr	for (i = 0; i <= IPL_LOGMAX; i++) {
271145516Sdarrenr		for (q = ip_pool_list[i]; (p = q) != NULL; ) {
272145516Sdarrenr			op.iplo_unit = i;
273145516Sdarrenr			(void)strncpy(op.iplo_name, p->ipo_name,
274145516Sdarrenr				sizeof(op.iplo_name));
275145516Sdarrenr			q = p->ipo_next;
276145516Sdarrenr			(void) ip_pool_destroy(&op);
277145516Sdarrenr		}
278145516Sdarrenr	}
279145516Sdarrenr
280145516Sdarrenr#if (!defined(_KERNEL) || (BSD < 199306))
281145516Sdarrenr	rn_fini();
282145516Sdarrenr#endif
283145516Sdarrenr}
284145516Sdarrenr
285145516Sdarrenr
286145516Sdarrenr/* ------------------------------------------------------------------------ */
287145516Sdarrenr/* Function:    ip_pool_statistics                                          */
288145516Sdarrenr/* Returns:     int     - 0 = success, else error                           */
289145516Sdarrenr/* Parameters:  op(I)   - pointer to lookup operation arguments             */
290145516Sdarrenr/*                                                                          */
291145516Sdarrenr/* Copy the current statistics out into user space, collecting pool list    */
292145516Sdarrenr/* pointers as appropriate for later use.                                   */
293145516Sdarrenr/* ------------------------------------------------------------------------ */
294145516Sdarrenrint ip_pool_statistics(op)
295145516Sdarrenriplookupop_t *op;
296145516Sdarrenr{
297145516Sdarrenr	ip_pool_stat_t stats;
298145516Sdarrenr	int unit, i, err = 0;
299145516Sdarrenr
300145516Sdarrenr	if (op->iplo_size != sizeof(ipoolstat))
301145516Sdarrenr		return EINVAL;
302145516Sdarrenr
303145516Sdarrenr	bcopy((char *)&ipoolstat, (char *)&stats, sizeof(stats));
304145516Sdarrenr	unit = op->iplo_unit;
305145516Sdarrenr	if (unit == IPL_LOGALL) {
306145516Sdarrenr		for (i = 0; i < IPL_LOGSIZE; i++)
307145516Sdarrenr			stats.ipls_list[i] = ip_pool_list[i];
308145516Sdarrenr	} else if (unit >= 0 && unit < IPL_LOGSIZE) {
309145516Sdarrenr		if (op->iplo_name[0] != '\0')
310145516Sdarrenr			stats.ipls_list[unit] = ip_pool_find(unit,
311145516Sdarrenr							     op->iplo_name);
312145516Sdarrenr		else
313145516Sdarrenr			stats.ipls_list[unit] = ip_pool_list[unit];
314145516Sdarrenr	} else
315145516Sdarrenr		err = EINVAL;
316145516Sdarrenr	if (err == 0)
317145516Sdarrenr		err = COPYOUT(&stats, op->iplo_struct, sizeof(stats));
318145516Sdarrenr	return err;
319145516Sdarrenr}
320145516Sdarrenr
321145516Sdarrenr
322145516Sdarrenr
323145516Sdarrenr/* ------------------------------------------------------------------------ */
324145516Sdarrenr/* Function:    ip_pool_find                                                */
325145516Sdarrenr/* Returns:     int     - 0 = success, else error                           */
326145516Sdarrenr/* Parameters:  ipo(I)  - pointer to the pool getting the new node.         */
327145516Sdarrenr/*                                                                          */
328145516Sdarrenr/* Find a matching pool inside the collection of pools for a particular     */
329145516Sdarrenr/* device, indicated by the unit number.                                    */
330145516Sdarrenr/* ------------------------------------------------------------------------ */
331145516Sdarrenrvoid *ip_pool_find(unit, name)
332145516Sdarrenrint unit;
333145516Sdarrenrchar *name;
334145516Sdarrenr{
335145516Sdarrenr	ip_pool_t *p;
336145516Sdarrenr
337145516Sdarrenr	for (p = ip_pool_list[unit]; p != NULL; p = p->ipo_next)
338145516Sdarrenr		if (strncmp(p->ipo_name, name, sizeof(p->ipo_name)) == 0)
339145516Sdarrenr			break;
340145516Sdarrenr	return p;
341145516Sdarrenr}
342145516Sdarrenr
343145516Sdarrenr
344145516Sdarrenr/* ------------------------------------------------------------------------ */
345145516Sdarrenr/* Function:    ip_pool_findeq                                              */
346145516Sdarrenr/* Returns:     int     - 0 = success, else error                           */
347145516Sdarrenr/* Parameters:  ipo(I)  - pointer to the pool getting the new node.         */
348145516Sdarrenr/*              addr(I) - pointer to address information to delete          */
349145516Sdarrenr/*              mask(I) -                                                   */
350145516Sdarrenr/*                                                                          */
351145516Sdarrenr/* Searches for an exact match of an entry in the pool.                     */
352145516Sdarrenr/* ------------------------------------------------------------------------ */
353145516Sdarrenrip_pool_node_t *ip_pool_findeq(ipo, addr, mask)
354145516Sdarrenrip_pool_t *ipo;
355145516Sdarrenraddrfamily_t *addr, *mask;
356145516Sdarrenr{
357145516Sdarrenr	struct radix_node *n;
358153872Sguido	SPL_INT(s);
359145516Sdarrenr
360145516Sdarrenr	SPL_NET(s);
361145516Sdarrenr	RADIX_NODE_HEAD_LOCK(ipo->ipo_head);
362145516Sdarrenr	n = ipo->ipo_head->rnh_lookup(addr, mask, ipo->ipo_head);
363145516Sdarrenr	RADIX_NODE_HEAD_UNLOCK(ipo->ipo_head);
364145516Sdarrenr	SPL_X(s);
365145516Sdarrenr	return (ip_pool_node_t *)n;
366145516Sdarrenr}
367145516Sdarrenr
368145516Sdarrenr
369145516Sdarrenr/* ------------------------------------------------------------------------ */
370145516Sdarrenr/* Function:    ip_pool_search                                              */
371145516Sdarrenr/* Returns:     int     - 0 == +ve match, -1 == error, 1 == -ve/no match    */
372145516Sdarrenr/* Parameters:  tptr(I)    - pointer to the pool to search                  */
373145516Sdarrenr/*              version(I) - IP protocol version (4 or 6)                   */
374145516Sdarrenr/*              dptr(I)    - pointer to address information                 */
375145516Sdarrenr/*                                                                          */
376145516Sdarrenr/* Search the pool for a given address and return a search result.          */
377145516Sdarrenr/* ------------------------------------------------------------------------ */
378145516Sdarrenrint ip_pool_search(tptr, version, dptr)
379145516Sdarrenrvoid *tptr;
380145516Sdarrenrint version;
381145516Sdarrenrvoid *dptr;
382145516Sdarrenr{
383145516Sdarrenr	struct radix_node *rn;
384145516Sdarrenr	ip_pool_node_t *m;
385145516Sdarrenr	i6addr_t *addr;
386145516Sdarrenr	addrfamily_t v;
387145516Sdarrenr	ip_pool_t *ipo;
388145516Sdarrenr	int rv;
389145516Sdarrenr
390145516Sdarrenr	ipo = tptr;
391145516Sdarrenr	if (ipo == NULL)
392145516Sdarrenr		return -1;
393145516Sdarrenr
394145516Sdarrenr	rv = 1;
395145516Sdarrenr	m = NULL;
396145516Sdarrenr	addr = (i6addr_t *)dptr;
397145516Sdarrenr	bzero(&v, sizeof(v));
398145516Sdarrenr	v.adf_len = offsetof(addrfamily_t, adf_addr);
399145516Sdarrenr
400145516Sdarrenr	if (version == 4) {
401145516Sdarrenr		v.adf_len += sizeof(addr->in4);
402145516Sdarrenr		v.adf_addr.in4 = addr->in4;
403145516Sdarrenr#ifdef USE_INET6
404145516Sdarrenr	} else if (version == 6) {
405145516Sdarrenr		v.adf_len += sizeof(addr->in6);
406145516Sdarrenr		v.adf_addr.in6 = addr->in6;
407145516Sdarrenr#endif
408145516Sdarrenr	} else
409145516Sdarrenr		return -1;
410145516Sdarrenr
411145516Sdarrenr	READ_ENTER(&ip_poolrw);
412145516Sdarrenr
413145516Sdarrenr	RADIX_NODE_HEAD_LOCK(ipo->ipo_head);
414145516Sdarrenr	rn = ipo->ipo_head->rnh_matchaddr(&v, ipo->ipo_head);
415145516Sdarrenr	RADIX_NODE_HEAD_UNLOCK(ipo->ipo_head);
416145516Sdarrenr
417145516Sdarrenr	if ((rn != NULL) && ((rn->rn_flags & RNF_ROOT) == 0)) {
418145516Sdarrenr		m = (ip_pool_node_t *)rn;
419145516Sdarrenr		ipo->ipo_hits++;
420145516Sdarrenr		m->ipn_hits++;
421145516Sdarrenr		rv = m->ipn_info;
422145516Sdarrenr	}
423145516Sdarrenr	RWLOCK_EXIT(&ip_poolrw);
424145516Sdarrenr	return rv;
425145516Sdarrenr}
426145516Sdarrenr
427145516Sdarrenr
428145516Sdarrenr/* ------------------------------------------------------------------------ */
429145516Sdarrenr/* Function:    ip_pool_insert                                              */
430145516Sdarrenr/* Returns:     int     - 0 = success, else error                           */
431145516Sdarrenr/* Parameters:  ipo(I)  - pointer to the pool getting the new node.         */
432145516Sdarrenr/*              addr(I) - address being added as a node                     */
433145516Sdarrenr/*              mask(I) - netmask to with the node being added              */
434145516Sdarrenr/*              info(I) - extra information to store in this node.          */
435145516Sdarrenr/* Locks:       WRITE(ip_poolrw)                                            */
436145516Sdarrenr/*                                                                          */
437145516Sdarrenr/* Add another node to the pool given by ipo.  The three parameters passed  */
438145516Sdarrenr/* in (addr, mask, info) shold all be stored in the node.                   */
439145516Sdarrenr/* ------------------------------------------------------------------------ */
440145516Sdarrenrint ip_pool_insert(ipo, addr, mask, info)
441145516Sdarrenrip_pool_t *ipo;
442145516Sdarrenri6addr_t *addr, *mask;
443145516Sdarrenrint info;
444145516Sdarrenr{
445145516Sdarrenr	struct radix_node *rn;
446145516Sdarrenr	ip_pool_node_t *x;
447145516Sdarrenr
448145516Sdarrenr	ASSERT(rw_read_locked(&ip_poolrw.ipf_lk) == 0);
449145516Sdarrenr
450145516Sdarrenr	KMALLOC(x, ip_pool_node_t *);
451145516Sdarrenr	if (x == NULL) {
452145516Sdarrenr		return ENOMEM;
453145516Sdarrenr	}
454145516Sdarrenr
455145516Sdarrenr	bzero(x, sizeof(*x));
456145516Sdarrenr
457145516Sdarrenr	x->ipn_info = info;
458145516Sdarrenr	(void)strncpy(x->ipn_name, ipo->ipo_name, sizeof(x->ipn_name));
459145516Sdarrenr
460145516Sdarrenr	bcopy(addr, &x->ipn_addr.adf_addr, sizeof(*addr));
461145516Sdarrenr	x->ipn_addr.adf_len = sizeof(x->ipn_addr);
462145516Sdarrenr	bcopy(mask, &x->ipn_mask.adf_addr, sizeof(*mask));
463145516Sdarrenr	x->ipn_mask.adf_len = sizeof(x->ipn_mask);
464145516Sdarrenr
465145516Sdarrenr	RADIX_NODE_HEAD_LOCK(ipo->ipo_head);
466145516Sdarrenr	rn = ipo->ipo_head->rnh_addaddr(&x->ipn_addr, &x->ipn_mask,
467145516Sdarrenr					ipo->ipo_head, x->ipn_nodes);
468145516Sdarrenr	RADIX_NODE_HEAD_UNLOCK(ipo->ipo_head);
469145516Sdarrenr#ifdef	DEBUG_POOL
470145516Sdarrenr	printf("Added %p at %p\n", x, rn);
471145516Sdarrenr#endif
472145516Sdarrenr
473145516Sdarrenr	if (rn == NULL) {
474145516Sdarrenr		KFREE(x);
475145516Sdarrenr		return ENOMEM;
476145516Sdarrenr	}
477145516Sdarrenr
478145516Sdarrenr	x->ipn_next = ipo->ipo_list;
479145516Sdarrenr	x->ipn_pnext = &ipo->ipo_list;
480145516Sdarrenr	if (ipo->ipo_list != NULL)
481145516Sdarrenr		ipo->ipo_list->ipn_pnext = &x->ipn_next;
482145516Sdarrenr	ipo->ipo_list = x;
483145516Sdarrenr
484145516Sdarrenr	ipoolstat.ipls_nodes++;
485145516Sdarrenr
486145516Sdarrenr	return 0;
487145516Sdarrenr}
488145516Sdarrenr
489145516Sdarrenr
490145516Sdarrenr/* ------------------------------------------------------------------------ */
491145516Sdarrenr/* Function:    ip_pool_create                                              */
492145516Sdarrenr/* Returns:     int     - 0 = success, else error                           */
493145516Sdarrenr/* Parameters:  op(I) - pointer to iplookup struct with call details        */
494145516Sdarrenr/* Locks:       WRITE(ip_poolrw)                                            */
495145516Sdarrenr/*                                                                          */
496145516Sdarrenr/* Creates a new group according to the paramters passed in via the         */
497145516Sdarrenr/* iplookupop structure.  Does not check to see if the group already exists */
498145516Sdarrenr/* when being inserted - assume this has already been done.  If the pool is */
499145516Sdarrenr/* marked as being anonymous, give it a new, unique, identifier.  Call any  */
500145516Sdarrenr/* other functions required to initialise the structure.                    */
501145516Sdarrenr/* ------------------------------------------------------------------------ */
502145516Sdarrenrint ip_pool_create(op)
503145516Sdarrenriplookupop_t *op;
504145516Sdarrenr{
505145516Sdarrenr	char name[FR_GROUPLEN];
506145516Sdarrenr	int poolnum, unit;
507145516Sdarrenr	ip_pool_t *h;
508145516Sdarrenr
509145516Sdarrenr	ASSERT(rw_read_locked(&ip_poolrw.ipf_lk) == 0);
510145516Sdarrenr
511145516Sdarrenr	KMALLOC(h, ip_pool_t *);
512145516Sdarrenr	if (h == NULL)
513145516Sdarrenr		return ENOMEM;
514145516Sdarrenr	bzero(h, sizeof(*h));
515145516Sdarrenr
516145516Sdarrenr	if (rn_inithead((void **)&h->ipo_head,
517145516Sdarrenr			offsetof(addrfamily_t, adf_addr) << 3) == 0) {
518145516Sdarrenr		KFREE(h);
519145516Sdarrenr		return ENOMEM;
520145516Sdarrenr	}
521145516Sdarrenr
522145516Sdarrenr	unit = op->iplo_unit;
523145516Sdarrenr
524145516Sdarrenr	if ((op->iplo_arg & IPOOL_ANON) != 0) {
525145516Sdarrenr		ip_pool_t *p;
526145516Sdarrenr
527145516Sdarrenr		poolnum = IPOOL_ANON;
528145516Sdarrenr
529145516Sdarrenr#if defined(SNPRINTF) && defined(_KERNEL)
530145516Sdarrenr		SNPRINTF(name, sizeof(name), "%x", poolnum);
531145516Sdarrenr#else
532145516Sdarrenr		(void)sprintf(name, "%x", poolnum);
533145516Sdarrenr#endif
534145516Sdarrenr
535145516Sdarrenr		for (p = ip_pool_list[unit]; p != NULL; ) {
536145516Sdarrenr			if (strncmp(name, p->ipo_name,
537145516Sdarrenr				    sizeof(p->ipo_name)) == 0) {
538145516Sdarrenr				poolnum++;
539145516Sdarrenr#if defined(SNPRINTF) && defined(_KERNEL)
540145516Sdarrenr				SNPRINTF(name, sizeof(name), "%x", poolnum);
541145516Sdarrenr#else
542145516Sdarrenr				(void)sprintf(name, "%x", poolnum);
543145516Sdarrenr#endif
544145516Sdarrenr				p = ip_pool_list[unit];
545145516Sdarrenr			} else
546145516Sdarrenr				p = p->ipo_next;
547145516Sdarrenr		}
548145516Sdarrenr
549145516Sdarrenr		(void)strncpy(h->ipo_name, name, sizeof(h->ipo_name));
550153872Sguido		(void)strncpy(op->iplo_name, name, sizeof(op->iplo_name));
551145516Sdarrenr	} else {
552145516Sdarrenr		(void) strncpy(h->ipo_name, op->iplo_name, sizeof(h->ipo_name));
553145516Sdarrenr	}
554145516Sdarrenr
555145516Sdarrenr	h->ipo_ref = 1;
556145516Sdarrenr	h->ipo_list = NULL;
557145516Sdarrenr	h->ipo_unit = unit;
558145516Sdarrenr	h->ipo_next = ip_pool_list[unit];
559145516Sdarrenr	if (ip_pool_list[unit] != NULL)
560145516Sdarrenr		ip_pool_list[unit]->ipo_pnext = &h->ipo_next;
561145516Sdarrenr	h->ipo_pnext = &ip_pool_list[unit];
562145516Sdarrenr	ip_pool_list[unit] = h;
563145516Sdarrenr
564145516Sdarrenr	ipoolstat.ipls_pools++;
565145516Sdarrenr
566145516Sdarrenr	return 0;
567145516Sdarrenr}
568145516Sdarrenr
569145516Sdarrenr
570145516Sdarrenr/* ------------------------------------------------------------------------ */
571145516Sdarrenr/* Function:    ip_pool_remove                                              */
572145516Sdarrenr/* Returns:     int    - 0 = success, else error                            */
573145516Sdarrenr/* Parameters:  ipo(I) - pointer to the pool to remove the node from.       */
574145516Sdarrenr/*              ipe(I) - address being deleted as a node                    */
575145516Sdarrenr/* Locks:       WRITE(ip_poolrw)                                            */
576145516Sdarrenr/*                                                                          */
577145516Sdarrenr/* Add another node to the pool given by ipo.  The three parameters passed  */
578145516Sdarrenr/* in (addr, mask, info) shold all be stored in the node.                   */
579145516Sdarrenr/* ------------------------------------------------------------------------ */
580145516Sdarrenrint ip_pool_remove(ipo, ipe)
581145516Sdarrenrip_pool_t *ipo;
582145516Sdarrenrip_pool_node_t *ipe;
583145516Sdarrenr{
584145516Sdarrenr	ip_pool_node_t **ipp, *n;
585145516Sdarrenr
586145516Sdarrenr	ASSERT(rw_read_locked(&ip_poolrw.ipf_lk) == 0);
587145516Sdarrenr
588145516Sdarrenr	for (ipp = &ipo->ipo_list; (n = *ipp) != NULL; ipp = &n->ipn_next) {
589145516Sdarrenr		if (ipe == n) {
590145516Sdarrenr			*n->ipn_pnext = n->ipn_next;
591145516Sdarrenr			if (n->ipn_next)
592145516Sdarrenr				n->ipn_next->ipn_pnext = n->ipn_pnext;
593145516Sdarrenr			break;
594145516Sdarrenr		}
595145516Sdarrenr	}
596145516Sdarrenr
597145516Sdarrenr	if (n == NULL)
598145516Sdarrenr		return ENOENT;
599145516Sdarrenr
600145516Sdarrenr	RADIX_NODE_HEAD_LOCK(ipo->ipo_head);
601145516Sdarrenr	ipo->ipo_head->rnh_deladdr(&n->ipn_addr, &n->ipn_mask,
602145516Sdarrenr				   ipo->ipo_head);
603145516Sdarrenr	RADIX_NODE_HEAD_UNLOCK(ipo->ipo_head);
604145516Sdarrenr	KFREE(n);
605145516Sdarrenr
606145516Sdarrenr	ipoolstat.ipls_nodes--;
607145516Sdarrenr
608145516Sdarrenr	return 0;
609145516Sdarrenr}
610145516Sdarrenr
611145516Sdarrenr
612145516Sdarrenr/* ------------------------------------------------------------------------ */
613145516Sdarrenr/* Function:    ip_pool_destroy                                             */
614145516Sdarrenr/* Returns:     int    - 0 = success, else error                            */
615145516Sdarrenr/* Parameters:  op(I)  -  information about the pool to remove              */
616145516Sdarrenr/* Locks:       WRITE(ip_poolrw) or WRITE(ipf_global)                       */
617145516Sdarrenr/*                                                                          */
618145516Sdarrenr/* Search for a pool using paramters passed in and if it's not otherwise    */
619145516Sdarrenr/* busy, free it.                                                           */
620145516Sdarrenr/*                                                                          */
621145516Sdarrenr/* NOTE: Because this function is called out of ipldetach() where ip_poolrw */
622145516Sdarrenr/* may not be initialised, we can't use an ASSERT to enforce the locking    */
623145516Sdarrenr/* assertion that one of the two (ip_poolrw,ipf_global) is held.            */
624145516Sdarrenr/* ------------------------------------------------------------------------ */
625145516Sdarrenrint ip_pool_destroy(op)
626145516Sdarrenriplookupop_t *op;
627145516Sdarrenr{
628145516Sdarrenr	ip_pool_t *ipo;
629145516Sdarrenr
630145516Sdarrenr	ipo = ip_pool_find(op->iplo_unit, op->iplo_name);
631145516Sdarrenr	if (ipo == NULL)
632145516Sdarrenr		return ESRCH;
633145516Sdarrenr
634145516Sdarrenr	if (ipo->ipo_ref != 1)
635145516Sdarrenr		return EBUSY;
636145516Sdarrenr
637145516Sdarrenr	ip_pool_free(ipo);
638145516Sdarrenr	return 0;
639145516Sdarrenr}
640145516Sdarrenr
641145516Sdarrenr
642145516Sdarrenr/* ------------------------------------------------------------------------ */
643145516Sdarrenr/* Function:    ip_pool_flush                                               */
644145516Sdarrenr/* Returns:     int    - number of pools deleted                            */
645145516Sdarrenr/* Parameters:  fp(I)  - which pool(s) to flush                             */
646145516Sdarrenr/* Locks:       WRITE(ip_poolrw) or WRITE(ipf_global)                       */
647145516Sdarrenr/*                                                                          */
648145516Sdarrenr/* Free all pools associated with the device that matches the unit number   */
649145516Sdarrenr/* passed in with operation.                                                */
650145516Sdarrenr/*                                                                          */
651145516Sdarrenr/* NOTE: Because this function is called out of ipldetach() 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/* ------------------------------------------------------------------------ */
655145516Sdarrenrint ip_pool_flush(fp)
656145516Sdarrenriplookupflush_t *fp;
657145516Sdarrenr{
658145516Sdarrenr	int i, num = 0, unit, err;
659145516Sdarrenr	ip_pool_t *p, *q;
660145516Sdarrenr	iplookupop_t op;
661145516Sdarrenr
662145516Sdarrenr	unit = fp->iplf_unit;
663145516Sdarrenr
664145516Sdarrenr	for (i = 0; i <= IPL_LOGMAX; i++) {
665145516Sdarrenr		if (unit != IPLT_ALL && i != unit)
666145516Sdarrenr			continue;
667145516Sdarrenr		for (q = ip_pool_list[i]; (p = q) != NULL; ) {
668145516Sdarrenr			op.iplo_unit = i;
669145516Sdarrenr			(void)strncpy(op.iplo_name, p->ipo_name,
670145516Sdarrenr				sizeof(op.iplo_name));
671145516Sdarrenr			q = p->ipo_next;
672145516Sdarrenr			err = ip_pool_destroy(&op);
673145516Sdarrenr			if (err == 0)
674145516Sdarrenr				num++;
675145516Sdarrenr			else
676145516Sdarrenr				break;
677145516Sdarrenr		}
678145516Sdarrenr	}
679145516Sdarrenr	return num;
680145516Sdarrenr}
681145516Sdarrenr
682145516Sdarrenr
683145516Sdarrenr/* ------------------------------------------------------------------------ */
684145516Sdarrenr/* Function:    ip_pool_free                                                */
685145516Sdarrenr/* Returns:     void                                                        */
686145516Sdarrenr/* Parameters:  ipo(I) -  pointer to pool structure                         */
687145516Sdarrenr/* Locks:       WRITE(ip_poolrw) or WRITE(ipf_global)                       */
688145516Sdarrenr/*                                                                          */
689145516Sdarrenr/* Deletes the pool strucutre passed in from the list of pools and deletes  */
690145516Sdarrenr/* all of the address information stored in it, including any tree data     */
691145516Sdarrenr/* structures also allocated.                                               */
692145516Sdarrenr/*                                                                          */
693145516Sdarrenr/* NOTE: Because this function is called out of ipldetach() where ip_poolrw */
694145516Sdarrenr/* may not be initialised, we can't use an ASSERT to enforce the locking    */
695145516Sdarrenr/* assertion that one of the two (ip_poolrw,ipf_global) is held.            */
696145516Sdarrenr/* ------------------------------------------------------------------------ */
697145516Sdarrenrvoid ip_pool_free(ipo)
698145516Sdarrenrip_pool_t *ipo;
699145516Sdarrenr{
700145516Sdarrenr	ip_pool_node_t *n;
701145516Sdarrenr
702145516Sdarrenr	RADIX_NODE_HEAD_LOCK(ipo->ipo_head);
703145516Sdarrenr	while ((n = ipo->ipo_list) != NULL) {
704145516Sdarrenr		ipo->ipo_head->rnh_deladdr(&n->ipn_addr, &n->ipn_mask,
705145516Sdarrenr					   ipo->ipo_head);
706145516Sdarrenr
707145516Sdarrenr		*n->ipn_pnext = n->ipn_next;
708145516Sdarrenr		if (n->ipn_next)
709145516Sdarrenr			n->ipn_next->ipn_pnext = n->ipn_pnext;
710145516Sdarrenr
711145516Sdarrenr		KFREE(n);
712145516Sdarrenr
713145516Sdarrenr		ipoolstat.ipls_nodes--;
714145516Sdarrenr	}
715145516Sdarrenr	RADIX_NODE_HEAD_UNLOCK(ipo->ipo_head);
716145516Sdarrenr
717145516Sdarrenr	ipo->ipo_list = NULL;
718145516Sdarrenr	if (ipo->ipo_next != NULL)
719145516Sdarrenr		ipo->ipo_next->ipo_pnext = ipo->ipo_pnext;
720145516Sdarrenr	*ipo->ipo_pnext = ipo->ipo_next;
721145516Sdarrenr	rn_freehead(ipo->ipo_head);
722145516Sdarrenr	KFREE(ipo);
723145516Sdarrenr
724145516Sdarrenr	ipoolstat.ipls_pools--;
725145516Sdarrenr}
726145516Sdarrenr
727145516Sdarrenr
728145516Sdarrenr/* ------------------------------------------------------------------------ */
729145516Sdarrenr/* Function:    ip_pool_deref                                               */
730145516Sdarrenr/* Returns:     void                                                        */
731145516Sdarrenr/* Parameters:  ipo(I) -  pointer to pool structure                         */
732145516Sdarrenr/* Locks:       WRITE(ip_poolrw)                                            */
733145516Sdarrenr/*                                                                          */
734145516Sdarrenr/* Drop the number of known references to this pool structure by one and if */
735145516Sdarrenr/* we arrive at zero known references, free it.                             */
736145516Sdarrenr/* ------------------------------------------------------------------------ */
737145516Sdarrenrvoid ip_pool_deref(ipo)
738145516Sdarrenrip_pool_t *ipo;
739145516Sdarrenr{
740145516Sdarrenr
741145516Sdarrenr	ASSERT(rw_read_locked(&ip_poolrw.ipf_lk) == 0);
742145516Sdarrenr
743145516Sdarrenr	ipo->ipo_ref--;
744145516Sdarrenr	if (ipo->ipo_ref == 0)
745145516Sdarrenr		ip_pool_free(ipo);
746145516Sdarrenr}
747145516Sdarrenr
748145516Sdarrenr
749145516Sdarrenr# if defined(_KERNEL) && ((BSD >= 198911) && !defined(__osf__) && \
750145516Sdarrenr      !defined(__hpux) && !defined(__sgi))
751145516Sdarrenrstatic int
752145516Sdarrenrrn_freenode(struct radix_node *n, void *p)
753145516Sdarrenr{
754145516Sdarrenr	struct radix_node_head *rnh = p;
755145516Sdarrenr	struct radix_node *d;
756145516Sdarrenr
757145516Sdarrenr	d = rnh->rnh_deladdr(n->rn_key, NULL, rnh);
758145516Sdarrenr	if (d != NULL) {
759145516Sdarrenr		FreeS(d, max_keylen + 2 * sizeof (*d));
760145516Sdarrenr	}
761145516Sdarrenr	return 0;
762145516Sdarrenr}
763145516Sdarrenr
764145516Sdarrenr
765145516Sdarrenrvoid
766145516Sdarrenrrn_freehead(rnh)
767145516Sdarrenr      struct radix_node_head *rnh;
768145516Sdarrenr{
769145516Sdarrenr
770145516Sdarrenr	RADIX_NODE_HEAD_LOCK(rnh);
771145516Sdarrenr	(*rnh->rnh_walktree)(rnh, rn_freenode, rnh);
772145516Sdarrenr
773145516Sdarrenr	rnh->rnh_addaddr = NULL;
774145516Sdarrenr	rnh->rnh_deladdr = NULL;
775145516Sdarrenr	rnh->rnh_matchaddr = NULL;
776145516Sdarrenr	rnh->rnh_lookup = NULL;
777145516Sdarrenr	rnh->rnh_walktree = NULL;
778145516Sdarrenr	RADIX_NODE_HEAD_UNLOCK(rnh);
779145516Sdarrenr
780145516Sdarrenr	Free(rnh);
781145516Sdarrenr}
782145516Sdarrenr# endif
783145516Sdarrenr
784145516Sdarrenr#endif /* IPFILTER_LOOKUP */
785