xref: /illumos-gate/usr/src/uts/common/inet/ipf/ip_pool.c (revision 0173c38a73f34277e0c97a19fedfd25d81ba8380)
1 /*
2  * Copyright (C) 1993-2001, 2003 by Darren Reed.
3  *
4  * See the IPFILTER.LICENCE file for details on licencing.
5  *
6  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
7  * Use is subject to license terms.
8  */
9 
10 #pragma ident	"%Z%%M%	%I%	%E% SMI"
11 
12 #if defined(KERNEL) || defined(_KERNEL)
13 # undef KERNEL
14 # undef _KERNEL
15 # define        KERNEL	1
16 # define        _KERNEL	1
17 #endif
18 #if defined(__osf__)
19 # define _PROTO_NET_H_
20 #endif
21 #include <sys/errno.h>
22 #include <sys/types.h>
23 #include <sys/param.h>
24 #include <sys/file.h>
25 #if !defined(_KERNEL) && !defined(__KERNEL__)
26 # include <stdio.h>
27 # include <stdlib.h>
28 # include <string.h>
29 # define _KERNEL
30 # ifdef __OpenBSD__
31 struct file;
32 # endif
33 # include <sys/uio.h>
34 # undef _KERNEL
35 #else
36 # include <sys/systm.h>
37 # if defined(NetBSD) && (__NetBSD_Version__ >= 104000000)
38 #  include <sys/proc.h>
39 # endif
40 #endif
41 #include <sys/time.h>
42 #if !defined(linux)
43 # include <sys/protosw.h>
44 #endif
45 #include <sys/socket.h>
46 #if defined(_KERNEL) && (!defined(__SVR4) && !defined(__svr4__))
47 # include <sys/mbuf.h>
48 #endif
49 #if defined(__SVR4) || defined(__svr4__)
50 # include <sys/filio.h>
51 # include <sys/byteorder.h>
52 # ifdef _KERNEL
53 #  include <sys/dditypes.h>
54 # endif
55 # include <sys/stream.h>
56 # include <sys/kmem.h>
57 #endif
58 #if defined(__FreeBSD_version) && (__FreeBSD_version >= 300000)
59 # include <sys/malloc.h>
60 #endif
61 
62 #if defined(_KERNEL) && (defined(__osf__) || defined(AIX) || \
63      defined(__hpux) || defined(__sgi))
64 # ifdef __osf__
65 #  include <net/radix.h>
66 # endif
67 # include "radix_ipf_local.h"
68 # define _RADIX_H_
69 #endif
70 #include <net/if.h>
71 #include <netinet/in.h>
72 
73 #include "netinet/ip_compat.h"
74 #include "netinet/ip_fil.h"
75 #include "netinet/ip_pool.h"
76 
77 #if defined(IPFILTER_LOOKUP) && defined(_KERNEL) && \
78       ((BSD >= 198911) && !defined(__osf__) && \
79       !defined(__hpux) && !defined(__sgi))
80 static int rn_freenode __P((struct radix_node *, void *));
81 #endif
82 
83 /* END OF INCLUDES */
84 
85 #if !defined(lint)
86 static const char sccsid[] = "@(#)ip_fil.c	2.41 6/5/96 (C) 1993-2000 Darren Reed";
87 static const char rcsid[] = "@(#)$Id: ip_pool.c,v 2.55.2.14 2005/06/12 07:18:26 darrenr Exp $";
88 #endif
89 
90 #ifdef IPFILTER_LOOKUP
91 
92 ip_pool_stat_t ipoolstat;
93 ipfrwlock_t ip_poolrw;
94 
95 /*
96  * Binary tree routines from Sedgewick and enhanced to do ranges of addresses.
97  * NOTE: Insertion *MUST* be from greatest range to least for it to work!
98  * These should be replaced, eventually, by something else - most notably a
99  * interval searching method.  The important feature is to be able to find
100  * the best match.
101  *
102  * So why not use a radix tree for this?  As the first line implies, it
103  * has been written to work with a _range_ of addresses.  A range is not
104  * necessarily a match with any given netmask so what we end up dealing
105  * with is an interval tree.  Implementations of these are hard to find
106  * and the one herein is far from bug free.
107  *
108  * Sigh, in the end I became convinced that the bugs the code contained did
109  * not make it worthwhile not using radix trees.  For now the radix tree from
110  * 4.4 BSD is used, but this is not viewed as a long term solution.
111  */
112 ip_pool_t *ip_pool_list[IPL_LOGSIZE] = { NULL, NULL, NULL, NULL,
113 					 NULL, NULL, NULL, NULL };
114 
115 
116 #ifdef TEST_POOL
117 void treeprint __P((ip_pool_t *));
118 
119 int
120 main(argc, argv)
121 	int argc;
122 	char *argv[];
123 {
124 	addrfamily_t a, b;
125 	iplookupop_t op;
126 	ip_pool_t *ipo;
127 	i6addr_t ip;
128 
129 	RWLOCK_INIT(&ip_poolrw, "poolrw");
130 	ip_pool_init();
131 
132 	bzero((char *)&a, sizeof(a));
133 	bzero((char *)&b, sizeof(b));
134 	bzero((char *)&ip, sizeof(ip));
135 	bzero((char *)&op, sizeof(op));
136 	strcpy(op.iplo_name, "0");
137 
138 	if (ip_pool_create(&op) == 0)
139 		ipo = ip_pool_find(0, "0");
140 
141 	a.adf_addr.in4.s_addr = 0x0a010203;
142 	b.adf_addr.in4.s_addr = 0xffffffff;
143 	ip_pool_insert(ipo, &a, &b, 1);
144 	ip_pool_insert(ipo, &a, &b, 1);
145 
146 	a.adf_addr.in4.s_addr = 0x0a000000;
147 	b.adf_addr.in4.s_addr = 0xff000000;
148 	ip_pool_insert(ipo, &a, &b, 0);
149 	ip_pool_insert(ipo, &a, &b, 0);
150 
151 	a.adf_addr.in4.s_addr = 0x0a010100;
152 	b.adf_addr.in4.s_addr = 0xffffff00;
153 	ip_pool_insert(ipo, &a, &b, 1);
154 	ip_pool_insert(ipo, &a, &b, 1);
155 
156 	a.adf_addr.in4.s_addr = 0x0a010200;
157 	b.adf_addr.in4.s_addr = 0xffffff00;
158 	ip_pool_insert(ipo, &a, &b, 0);
159 	ip_pool_insert(ipo, &a, &b, 0);
160 
161 	a.adf_addr.in4.s_addr = 0x0a010000;
162 	b.adf_addr.in4.s_addr = 0xffff0000;
163 	ip_pool_insert(ipo, &a, &b, 1);
164 	ip_pool_insert(ipo, &a, &b, 1);
165 
166 	a.adf_addr.in4.s_addr = 0x0a01020f;
167 	b.adf_addr.in4.s_addr = 0xffffffff;
168 	ip_pool_insert(ipo, &a, &b, 1);
169 	ip_pool_insert(ipo, &a, &b, 1);
170 #ifdef	DEBUG_POOL
171 treeprint(ipo);
172 #endif
173 	ip.in4.s_addr = 0x0a00aabb;
174 	printf("search(%#x) = %d (0)\n", ip.in4.s_addr,
175 		ip_pool_search(ipo, 4, &ip));
176 
177 	ip.in4.s_addr = 0x0a000001;
178 	printf("search(%#x) = %d (0)\n", ip.in4.s_addr,
179 		ip_pool_search(ipo, 4, &ip));
180 
181 	ip.in4.s_addr = 0x0a000101;
182 	printf("search(%#x) = %d (0)\n", ip.in4.s_addr,
183 		ip_pool_search(ipo, 4, &ip));
184 
185 	ip.in4.s_addr = 0x0a010001;
186 	printf("search(%#x) = %d (1)\n", ip.in4.s_addr,
187 		ip_pool_search(ipo, 4, &ip));
188 
189 	ip.in4.s_addr = 0x0a010101;
190 	printf("search(%#x) = %d (1)\n", ip.in4.s_addr,
191 		ip_pool_search(ipo, 4, &ip));
192 
193 	ip.in4.s_addr = 0x0a010201;
194 	printf("search(%#x) = %d (0)\n", ip.in4.s_addr,
195 		ip_pool_search(ipo, 4, &ip));
196 
197 	ip.in4.s_addr = 0x0a010203;
198 	printf("search(%#x) = %d (1)\n", ip.in4.s_addr,
199 		ip_pool_search(ipo, 4, &ip));
200 
201 	ip.in4.s_addr = 0x0a01020f;
202 	printf("search(%#x) = %d (1)\n", ip.in4.s_addr,
203 		ip_pool_search(ipo, 4, &ip));
204 
205 	ip.in4.s_addr = 0x0b00aabb;
206 	printf("search(%#x) = %d (-1)\n", ip.in4.s_addr,
207 		ip_pool_search(ipo, 4, &ip));
208 
209 #ifdef	DEBUG_POOL
210 treeprint(ipo);
211 #endif
212 
213 	ip_pool_fini();
214 
215 	return 0;
216 }
217 
218 
219 void
220 treeprint(ipo)
221 ip_pool_t *ipo;
222 {
223 	ip_pool_node_t *c;
224 
225 	for (c = ipo->ipo_list; c != NULL; c = c->ipn_next)
226 		printf("Node %p(%s) (%#x/%#x) = %d hits %lu\n",
227 			c, c->ipn_name, c->ipn_addr.adf_addr.in4.s_addr,
228 			c->ipn_mask.adf_addr.in4.s_addr,
229 			c->ipn_info, c->ipn_hits);
230 }
231 #endif /* TEST_POOL */
232 
233 
234 /* ------------------------------------------------------------------------ */
235 /* Function:    ip_pool_init                                                */
236 /* Returns:     int     - 0 = success, else error                           */
237 /*                                                                          */
238 /* Initialise the routing table data structures where required.             */
239 /* ------------------------------------------------------------------------ */
240 int ip_pool_init()
241 {
242 
243 	bzero((char *)&ipoolstat, sizeof(ipoolstat));
244 
245 #if !defined(_KERNEL) || ((BSD < 199306) && (SOLARIS2 < 10))
246 	rn_init();
247 #endif
248 	return 0;
249 }
250 
251 
252 /* ------------------------------------------------------------------------ */
253 /* Function:    ip_pool_fini                                                */
254 /* Returns:     int     - 0 = success, else error                           */
255 /* Locks:       WRITE(ipf_global)                                           */
256 /*                                                                          */
257 /* Clean up all the pool data structures allocated and call the cleanup     */
258 /* function for the radix tree that supports the pools. ip_pool_destroy() is*/
259 /* used to delete the pools one by one to ensure they're properly freed up. */
260 /* ------------------------------------------------------------------------ */
261 void ip_pool_fini()
262 {
263 	ip_pool_t *p, *q;
264 	iplookupop_t op;
265 	int i;
266 
267 	ASSERT(rw_read_locked(&ipf_global.ipf_lk) == 0);
268 
269 	for (i = 0; i <= IPL_LOGMAX; i++) {
270 		for (q = ip_pool_list[i]; (p = q) != NULL; ) {
271 			op.iplo_unit = i;
272 			(void)strncpy(op.iplo_name, p->ipo_name,
273 				sizeof(op.iplo_name));
274 			q = p->ipo_next;
275 			(void) ip_pool_destroy(&op);
276 		}
277 	}
278 
279 #if !defined(_KERNEL) || ((BSD < 199306) && (SOLARIS2 < 10))
280 	rn_fini();
281 #endif
282 }
283 
284 
285 /* ------------------------------------------------------------------------ */
286 /* Function:    ip_pool_statistics                                          */
287 /* Returns:     int     - 0 = success, else error                           */
288 /* Parameters:  op(I)   - pointer to lookup operation arguments             */
289 /*                                                                          */
290 /* Copy the current statistics out into user space, collecting pool list    */
291 /* pointers as appropriate for later use.                                   */
292 /* ------------------------------------------------------------------------ */
293 int ip_pool_statistics(op)
294 iplookupop_t *op;
295 {
296 	ip_pool_stat_t stats;
297 	int unit, i, err = 0;
298 
299 	if (op->iplo_size != sizeof(ipoolstat))
300 		return EINVAL;
301 
302 	bcopy((char *)&ipoolstat, (char *)&stats, sizeof(stats));
303 	unit = op->iplo_unit;
304 	if (unit == IPL_LOGALL) {
305 		for (i = 0; i < IPL_LOGSIZE; i++)
306 			stats.ipls_list[i] = ip_pool_list[i];
307 	} else if (unit >= 0 && unit < IPL_LOGSIZE) {
308 		if (op->iplo_name[0] != '\0')
309 			stats.ipls_list[unit] = ip_pool_find(unit,
310 							     op->iplo_name);
311 		else
312 			stats.ipls_list[unit] = ip_pool_list[unit];
313 	} else
314 		err = EINVAL;
315 	if (err == 0)
316 		err = COPYOUT(&stats, op->iplo_struct, sizeof(stats));
317 	return err;
318 }
319 
320 
321 
322 /* ------------------------------------------------------------------------ */
323 /* Function:    ip_pool_find                                                */
324 /* Returns:     int     - 0 = success, else error                           */
325 /* Parameters:  ipo(I)  - pointer to the pool getting the new node.         */
326 /*                                                                          */
327 /* Find a matching pool inside the collection of pools for a particular     */
328 /* device, indicated by the unit number.                                    */
329 /* ------------------------------------------------------------------------ */
330 void *ip_pool_find(unit, name)
331 int unit;
332 char *name;
333 {
334 	ip_pool_t *p;
335 
336 	for (p = ip_pool_list[unit]; p != NULL; p = p->ipo_next)
337 		if (strncmp(p->ipo_name, name, sizeof(p->ipo_name)) == 0)
338 			break;
339 	return p;
340 }
341 
342 
343 /* ------------------------------------------------------------------------ */
344 /* Function:    ip_pool_findeq                                              */
345 /* Returns:     int     - 0 = success, else error                           */
346 /* Parameters:  ipo(I)  - pointer to the pool getting the new node.         */
347 /*              addr(I) - pointer to address information to delete          */
348 /*              mask(I) -                                                   */
349 /*                                                                          */
350 /* Searches for an exact match of an entry in the pool.                     */
351 /* ------------------------------------------------------------------------ */
352 ip_pool_node_t *ip_pool_findeq(ipo, addr, mask)
353 ip_pool_t *ipo;
354 addrfamily_t *addr, *mask;
355 {
356 	struct radix_node *n;
357 	SPL_INT(s);
358 
359 	SPL_NET(s);
360 	n = ipo->ipo_head->rnh_lookup(addr, mask, ipo->ipo_head);
361 	SPL_X(s);
362 	return (ip_pool_node_t *)n;
363 }
364 
365 
366 /* ------------------------------------------------------------------------ */
367 /* Function:    ip_pool_search                                              */
368 /* Returns:     int     - 0 == +ve match, -1 == error, 1 == -ve/no match    */
369 /* Parameters:  tptr(I)    - pointer to the pool to search                  */
370 /*              version(I) - IP protocol version (4 or 6)                   */
371 /*              dptr(I)    - pointer to address information                 */
372 /*                                                                          */
373 /* Search the pool for a given address and return a search result.          */
374 /* ------------------------------------------------------------------------ */
375 int ip_pool_search(tptr, version, dptr)
376 void *tptr;
377 int version;
378 void *dptr;
379 {
380 	struct radix_node *rn;
381 	ip_pool_node_t *m;
382 	i6addr_t *addr;
383 	addrfamily_t v;
384 	ip_pool_t *ipo;
385 	int rv;
386 
387 	ipo = tptr;
388 	if (ipo == NULL)
389 		return -1;
390 
391 	rv = 1;
392 	m = NULL;
393 	addr = (i6addr_t *)dptr;
394 	bzero(&v, sizeof(v));
395 	v.adf_len = offsetof(addrfamily_t, adf_addr);
396 
397 	if (version == 4) {
398 		v.adf_len += sizeof(addr->in4);
399 		v.adf_addr.in4 = addr->in4;
400 #ifdef USE_INET6
401 	} else if (version == 6) {
402 		v.adf_len += sizeof(addr->in6);
403 		v.adf_addr.in6 = addr->in6;
404 #endif
405 	} else
406 		return -1;
407 
408 	READ_ENTER(&ip_poolrw);
409 
410 	rn = ipo->ipo_head->rnh_matchaddr(&v, ipo->ipo_head);
411 
412 	if ((rn != NULL) && ((rn->rn_flags & RNF_ROOT) == 0)) {
413 		m = (ip_pool_node_t *)rn;
414 		ipo->ipo_hits++;
415 		m->ipn_hits++;
416 		rv = m->ipn_info;
417 	}
418 	RWLOCK_EXIT(&ip_poolrw);
419 	return rv;
420 }
421 
422 
423 /* ------------------------------------------------------------------------ */
424 /* Function:    ip_pool_insert                                              */
425 /* Returns:     int     - 0 = success, else error                           */
426 /* Parameters:  ipo(I)  - pointer to the pool getting the new node.         */
427 /*              addr(I) - IPv4/6 address being added as a node              */
428 /*              mask(I) - IPv4/6 netmask to with the node being added       */
429 /*              info(I) - extra information to store in this node.          */
430 /* Locks:       WRITE(ip_poolrw)                                            */
431 /*                                                                          */
432 /* Add another node to the pool given by ipo.  The three parameters passed  */
433 /* in (addr, mask, info) shold all be stored in the node.                   */
434 /* ------------------------------------------------------------------------ */
435 int ip_pool_insert(ipo, addr, mask, info)
436 ip_pool_t *ipo;
437 addrfamily_t *addr, *mask;
438 int info;
439 {
440 	struct radix_node *rn;
441 	ip_pool_node_t *x;
442 
443 	ASSERT(rw_read_locked(&ip_poolrw.ipf_lk) == 0);
444 
445 	KMALLOC(x, ip_pool_node_t *);
446 	if (x == NULL) {
447 		return ENOMEM;
448 	}
449 
450 	bzero(x, sizeof(*x));
451 
452 	x->ipn_info = info;
453 	(void)strncpy(x->ipn_name, ipo->ipo_name, sizeof(x->ipn_name));
454 
455 	bcopy(addr, &x->ipn_addr, sizeof(*addr));
456 	x->ipn_addr.adf_len = sizeof(x->ipn_addr);
457 	bcopy(mask, &x->ipn_mask, sizeof(*mask));
458 	x->ipn_mask.adf_len = sizeof(x->ipn_mask);
459 
460 	rn = ipo->ipo_head->rnh_addaddr(&x->ipn_addr, &x->ipn_mask,
461 					ipo->ipo_head, x->ipn_nodes);
462 #ifdef	DEBUG_POOL
463 	printf("Added %p at %p\n", x, rn);
464 #endif
465 
466 	if (rn == NULL) {
467 		KFREE(x);
468 		return ENOMEM;
469 	}
470 
471 	x->ipn_next = ipo->ipo_list;
472 	x->ipn_pnext = &ipo->ipo_list;
473 	if (ipo->ipo_list != NULL)
474 		ipo->ipo_list->ipn_pnext = &x->ipn_next;
475 	ipo->ipo_list = x;
476 
477 	ipoolstat.ipls_nodes++;
478 
479 	return 0;
480 }
481 
482 
483 /* ------------------------------------------------------------------------ */
484 /* Function:    ip_pool_create                                              */
485 /* Returns:     int     - 0 = success, else error                           */
486 /* Parameters:  op(I) - pointer to iplookup struct with call details        */
487 /* Locks:       WRITE(ip_poolrw)                                            */
488 /*                                                                          */
489 /* Creates a new group according to the paramters passed in via the         */
490 /* iplookupop structure.  Does not check to see if the group already exists */
491 /* when being inserted - assume this has already been done.  If the pool is */
492 /* marked as being anonymous, give it a new, unique, identifier.  Call any  */
493 /* other functions required to initialise the structure.                    */
494 /* ------------------------------------------------------------------------ */
495 int ip_pool_create(op)
496 iplookupop_t *op;
497 {
498 	char name[FR_GROUPLEN];
499 	int poolnum, unit;
500 	ip_pool_t *h;
501 
502 	ASSERT(rw_read_locked(&ip_poolrw.ipf_lk) == 0);
503 
504 	KMALLOC(h, ip_pool_t *);
505 	if (h == NULL)
506 		return ENOMEM;
507 	bzero(h, sizeof(*h));
508 
509 	if (rn_inithead((void **)&h->ipo_head,
510 			offsetof(addrfamily_t, adf_addr) << 3) == 0) {
511 		KFREE(h);
512 		return ENOMEM;
513 	}
514 
515 	unit = op->iplo_unit;
516 
517 	if ((op->iplo_arg & IPOOL_ANON) != 0) {
518 		ip_pool_t *p;
519 
520 		poolnum = IPOOL_ANON;
521 
522 #if defined(SNPRINTF) && defined(_KERNEL)
523 		(void)SNPRINTF(name, sizeof(name), "%x", poolnum);
524 #else
525 		(void)sprintf(name, "%x", poolnum);
526 #endif
527 
528 		for (p = ip_pool_list[unit]; p != NULL; ) {
529 			if (strncmp(name, p->ipo_name,
530 				    sizeof(p->ipo_name)) == 0) {
531 				poolnum++;
532 #if defined(SNPRINTF) && defined(_KERNEL)
533 				(void)SNPRINTF(name, sizeof(name), "%x", poolnum);
534 #else
535 				(void)sprintf(name, "%x", poolnum);
536 #endif
537 				p = ip_pool_list[unit];
538 			} else
539 				p = p->ipo_next;
540 		}
541 
542 		(void)strncpy(h->ipo_name, name, sizeof(h->ipo_name));
543 	} else {
544 		(void) strncpy(h->ipo_name, op->iplo_name, sizeof(h->ipo_name));
545 	}
546 
547 	h->ipo_ref = 1;
548 	h->ipo_list = NULL;
549 	h->ipo_unit = unit;
550 	h->ipo_next = ip_pool_list[unit];
551 	if (ip_pool_list[unit] != NULL)
552 		ip_pool_list[unit]->ipo_pnext = &h->ipo_next;
553 	h->ipo_pnext = &ip_pool_list[unit];
554 	ip_pool_list[unit] = h;
555 
556 	ipoolstat.ipls_pools++;
557 
558 	return 0;
559 }
560 
561 
562 /* ------------------------------------------------------------------------ */
563 /* Function:    ip_pool_remove                                              */
564 /* Returns:     int    - 0 = success, else error                            */
565 /* Parameters:  ipo(I) - pointer to the pool to remove the node from.       */
566 /*              ipe(I) - address being deleted as a node                    */
567 /* Locks:       WRITE(ip_poolrw)                                            */
568 /*                                                                          */
569 /* Add another node to the pool given by ipo.  The three parameters passed  */
570 /* in (addr, mask, info) shold all be stored in the node.                   */
571 /* ------------------------------------------------------------------------ */
572 int ip_pool_remove(ipo, ipe)
573 ip_pool_t *ipo;
574 ip_pool_node_t *ipe;
575 {
576 	ip_pool_node_t **ipp, *n;
577 
578 	ASSERT(rw_read_locked(&ip_poolrw.ipf_lk) == 0);
579 
580 	for (ipp = &ipo->ipo_list; (n = *ipp) != NULL; ipp = &n->ipn_next) {
581 		if (ipe == n) {
582 			*n->ipn_pnext = n->ipn_next;
583 			if (n->ipn_next)
584 				n->ipn_next->ipn_pnext = n->ipn_pnext;
585 			break;
586 		}
587 	}
588 
589 	if (n == NULL)
590 		return ENOENT;
591 
592 	ipo->ipo_head->rnh_deladdr(&n->ipn_addr, &n->ipn_mask,
593 				   ipo->ipo_head);
594 	KFREE(n);
595 
596 	ipoolstat.ipls_nodes--;
597 
598 	return 0;
599 }
600 
601 
602 /* ------------------------------------------------------------------------ */
603 /* Function:    ip_pool_destroy                                             */
604 /* Returns:     int    - 0 = success, else error                            */
605 /* Parameters:  op(I)  -  information about the pool to remove              */
606 /* Locks:       WRITE(ip_poolrw) or WRITE(ipf_global)                       */
607 /*                                                                          */
608 /* Search for a pool using paramters passed in and if it's not otherwise    */
609 /* busy, free it.                                                           */
610 /*                                                                          */
611 /* NOTE: Because this function is called out of ipldetach() where ip_poolrw */
612 /* may not be initialised, we can't use an ASSERT to enforce the locking    */
613 /* assertion that one of the two (ip_poolrw,ipf_global) is held.            */
614 /* ------------------------------------------------------------------------ */
615 int ip_pool_destroy(op)
616 iplookupop_t *op;
617 {
618 	ip_pool_t *ipo;
619 
620 	ipo = ip_pool_find(op->iplo_unit, op->iplo_name);
621 	if (ipo == NULL)
622 		return ESRCH;
623 
624 	if (ipo->ipo_ref != 1)
625 		return EBUSY;
626 
627 	ip_pool_free(ipo);
628 	return 0;
629 }
630 
631 
632 /* ------------------------------------------------------------------------ */
633 /* Function:    ip_pool_flush                                               */
634 /* Returns:     int    - number of pools deleted                            */
635 /* Parameters:  fp(I)  - which pool(s) to flush                             */
636 /* Locks:       WRITE(ip_poolrw) or WRITE(ipf_global)                       */
637 /*                                                                          */
638 /* Free all pools associated with the device that matches the unit number   */
639 /* passed in with operation.                                                */
640 /*                                                                          */
641 /* NOTE: Because this function is called out of ipldetach() where ip_poolrw */
642 /* may not be initialised, we can't use an ASSERT to enforce the locking    */
643 /* assertion that one of the two (ip_poolrw,ipf_global) is held.            */
644 /* ------------------------------------------------------------------------ */
645 int ip_pool_flush(fp)
646 iplookupflush_t *fp;
647 {
648 	int i, num = 0, unit, err;
649 	ip_pool_t *p, *q;
650 	iplookupop_t op;
651 
652 	unit = fp->iplf_unit;
653 
654 	for (i = 0; i <= IPL_LOGMAX; i++) {
655 		if (unit != IPLT_ALL && i != unit)
656 			continue;
657 		for (q = ip_pool_list[i]; (p = q) != NULL; ) {
658 			op.iplo_unit = i;
659 			(void)strncpy(op.iplo_name, p->ipo_name,
660 				sizeof(op.iplo_name));
661 			q = p->ipo_next;
662 			err = ip_pool_destroy(&op);
663 			if (err == 0)
664 				num++;
665 			else
666 				break;
667 		}
668 	}
669 	return num;
670 }
671 
672 
673 /* ------------------------------------------------------------------------ */
674 /* Function:    ip_pool_free                                                */
675 /* Returns:     void                                                        */
676 /* Parameters:  ipo(I) -  pointer to pool structure                         */
677 /* Locks:       WRITE(ip_poolrw) or WRITE(ipf_global)                       */
678 /*                                                                          */
679 /* Deletes the pool strucutre passed in from the list of pools and deletes  */
680 /* all of the address information stored in it, including any tree data     */
681 /* structures also allocated.                                               */
682 /*                                                                          */
683 /* NOTE: Because this function is called out of ipldetach() where ip_poolrw */
684 /* may not be initialised, we can't use an ASSERT to enforce the locking    */
685 /* assertion that one of the two (ip_poolrw,ipf_global) is held.            */
686 /* ------------------------------------------------------------------------ */
687 void ip_pool_free(ipo)
688 ip_pool_t *ipo;
689 {
690 	ip_pool_node_t *n;
691 
692 	while ((n = ipo->ipo_list) != NULL) {
693 		ipo->ipo_head->rnh_deladdr(&n->ipn_addr, &n->ipn_mask,
694 					   ipo->ipo_head);
695 
696 		*n->ipn_pnext = n->ipn_next;
697 		if (n->ipn_next)
698 			n->ipn_next->ipn_pnext = n->ipn_pnext;
699 
700 		KFREE(n);
701 
702 		ipoolstat.ipls_nodes--;
703 	}
704 
705 	ipo->ipo_list = NULL;
706 	if (ipo->ipo_next != NULL)
707 		ipo->ipo_next->ipo_pnext = ipo->ipo_pnext;
708 	*ipo->ipo_pnext = ipo->ipo_next;
709 	rn_freehead(ipo->ipo_head);
710 	KFREE(ipo);
711 
712 	ipoolstat.ipls_pools--;
713 }
714 
715 
716 /* ------------------------------------------------------------------------ */
717 /* Function:    ip_pool_deref                                               */
718 /* Returns:     void                                                        */
719 /* Parameters:  ipo(I) -  pointer to pool structure                         */
720 /* Locks:       WRITE(ip_poolrw)                                            */
721 /*                                                                          */
722 /* Drop the number of known references to this pool structure by one and if */
723 /* we arrive at zero known references, free it.                             */
724 /* ------------------------------------------------------------------------ */
725 void ip_pool_deref(ipo)
726 ip_pool_t *ipo;
727 {
728 
729 	ASSERT(rw_read_locked(&ip_poolrw.ipf_lk) == 0);
730 
731 	ipo->ipo_ref--;
732 	if (ipo->ipo_ref == 0)
733 		ip_pool_free(ipo);
734 }
735 
736 
737 # if defined(_KERNEL) && ((BSD >= 198911) && !defined(__osf__) && \
738       !defined(__hpux) && !defined(__sgi))
739 static int
740 rn_freenode(struct radix_node *n, void *p)
741 {
742 	struct radix_node_head *rnh = p;
743 	struct radix_node *d;
744 
745 	d = rnh->rnh_deladdr(n->rn_key, NULL, rnh);
746 	if (d != NULL) {
747 		FreeS(d, max_keylen + 2 * sizeof (*d));
748 	}
749 	return 0;
750 }
751 
752 
753 void
754 rn_freehead(rnh)
755       struct radix_node_head *rnh;
756 {
757 
758 	(*rnh->rnh_walktree)(rnh, rn_freenode, rnh);
759 
760 	rnh->rnh_addaddr = NULL;
761 	rnh->rnh_deladdr = NULL;
762 	rnh->rnh_matchaddr = NULL;
763 	rnh->rnh_lookup = NULL;
764 	rnh->rnh_walktree = NULL;
765 
766 	Free(rnh);
767 }
768 # endif
769 
770 #endif /* IPFILTER_LOOKUP */
771