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