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