xref: /illumos-gate/usr/src/uts/common/inet/ipf/ip_pool.c (revision f4b3ec61)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * Copyright (C) 1993-2001, 2003 by Darren Reed.
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * See the IPFILTER.LICENCE file for details on licencing.
57c478bd9Sstevel@tonic-gate  *
6*f4b3ec61Sdh  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
77c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
87c478bd9Sstevel@tonic-gate  */
97c478bd9Sstevel@tonic-gate 
107c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
117c478bd9Sstevel@tonic-gate 
127c478bd9Sstevel@tonic-gate #if defined(KERNEL) || defined(_KERNEL)
137c478bd9Sstevel@tonic-gate # undef KERNEL
147c478bd9Sstevel@tonic-gate # undef _KERNEL
157c478bd9Sstevel@tonic-gate # define        KERNEL	1
167c478bd9Sstevel@tonic-gate # define        _KERNEL	1
177c478bd9Sstevel@tonic-gate #endif
18ab25eeb5Syz #if defined(__osf__)
19ab25eeb5Syz # define _PROTO_NET_H_
20ab25eeb5Syz #endif
217c478bd9Sstevel@tonic-gate #include <sys/errno.h>
227c478bd9Sstevel@tonic-gate #include <sys/types.h>
237c478bd9Sstevel@tonic-gate #include <sys/param.h>
247c478bd9Sstevel@tonic-gate #include <sys/file.h>
257c478bd9Sstevel@tonic-gate #if !defined(_KERNEL) && !defined(__KERNEL__)
267c478bd9Sstevel@tonic-gate # include <stdio.h>
277c478bd9Sstevel@tonic-gate # include <stdlib.h>
287c478bd9Sstevel@tonic-gate # include <string.h>
297c478bd9Sstevel@tonic-gate # define _KERNEL
307c478bd9Sstevel@tonic-gate # ifdef __OpenBSD__
317c478bd9Sstevel@tonic-gate struct file;
327c478bd9Sstevel@tonic-gate # endif
337c478bd9Sstevel@tonic-gate # include <sys/uio.h>
347c478bd9Sstevel@tonic-gate # undef _KERNEL
357c478bd9Sstevel@tonic-gate #else
367c478bd9Sstevel@tonic-gate # include <sys/systm.h>
377c478bd9Sstevel@tonic-gate # if defined(NetBSD) && (__NetBSD_Version__ >= 104000000)
387c478bd9Sstevel@tonic-gate #  include <sys/proc.h>
397c478bd9Sstevel@tonic-gate # endif
407c478bd9Sstevel@tonic-gate #endif
417c478bd9Sstevel@tonic-gate #include <sys/time.h>
427c478bd9Sstevel@tonic-gate #if !defined(linux)
437c478bd9Sstevel@tonic-gate # include <sys/protosw.h>
447c478bd9Sstevel@tonic-gate #endif
457c478bd9Sstevel@tonic-gate #include <sys/socket.h>
467c478bd9Sstevel@tonic-gate #if defined(_KERNEL) && (!defined(__SVR4) && !defined(__svr4__))
477c478bd9Sstevel@tonic-gate # include <sys/mbuf.h>
487c478bd9Sstevel@tonic-gate #endif
497c478bd9Sstevel@tonic-gate #if defined(__SVR4) || defined(__svr4__)
507c478bd9Sstevel@tonic-gate # include <sys/filio.h>
517c478bd9Sstevel@tonic-gate # include <sys/byteorder.h>
527c478bd9Sstevel@tonic-gate # ifdef _KERNEL
537c478bd9Sstevel@tonic-gate #  include <sys/dditypes.h>
547c478bd9Sstevel@tonic-gate # endif
557c478bd9Sstevel@tonic-gate # include <sys/stream.h>
567c478bd9Sstevel@tonic-gate # include <sys/kmem.h>
577c478bd9Sstevel@tonic-gate #endif
587c478bd9Sstevel@tonic-gate #if defined(__FreeBSD_version) && (__FreeBSD_version >= 300000)
597c478bd9Sstevel@tonic-gate # include <sys/malloc.h>
607c478bd9Sstevel@tonic-gate #endif
617c478bd9Sstevel@tonic-gate 
62ab25eeb5Syz #if defined(_KERNEL) && (defined(__osf__) || defined(AIX) || \
63ab25eeb5Syz      defined(__hpux) || defined(__sgi))
64ab25eeb5Syz # ifdef __osf__
65ab25eeb5Syz #  include <net/radix.h>
66ab25eeb5Syz # endif
67ab25eeb5Syz # include "radix_ipf_local.h"
68ab25eeb5Syz # define _RADIX_H_
69ab25eeb5Syz #endif
707c478bd9Sstevel@tonic-gate #include <net/if.h>
717c478bd9Sstevel@tonic-gate #include <netinet/in.h>
727c478bd9Sstevel@tonic-gate 
73*f4b3ec61Sdh #include "netinet/ipf_stack.h"
747c478bd9Sstevel@tonic-gate #include "netinet/ip_compat.h"
757c478bd9Sstevel@tonic-gate #include "netinet/ip_fil.h"
767c478bd9Sstevel@tonic-gate #include "netinet/ip_pool.h"
77ab25eeb5Syz 
78ab25eeb5Syz #if defined(IPFILTER_LOOKUP) && defined(_KERNEL) && \
79ab25eeb5Syz       ((BSD >= 198911) && !defined(__osf__) && \
80ab25eeb5Syz       !defined(__hpux) && !defined(__sgi))
81ab25eeb5Syz static int rn_freenode __P((struct radix_node *, void *));
827c478bd9Sstevel@tonic-gate #endif
83ab25eeb5Syz 
847c478bd9Sstevel@tonic-gate /* END OF INCLUDES */
857c478bd9Sstevel@tonic-gate 
867c478bd9Sstevel@tonic-gate #if !defined(lint)
877c478bd9Sstevel@tonic-gate static const char sccsid[] = "@(#)ip_fil.c	2.41 6/5/96 (C) 1993-2000 Darren Reed";
88ab25eeb5Syz static const char rcsid[] = "@(#)$Id: ip_pool.c,v 2.55.2.14 2005/06/12 07:18:26 darrenr Exp $";
897c478bd9Sstevel@tonic-gate #endif
907c478bd9Sstevel@tonic-gate 
917c478bd9Sstevel@tonic-gate #ifdef IPFILTER_LOOKUP
927c478bd9Sstevel@tonic-gate 
937c478bd9Sstevel@tonic-gate /*
947c478bd9Sstevel@tonic-gate  * Binary tree routines from Sedgewick and enhanced to do ranges of addresses.
957c478bd9Sstevel@tonic-gate  * NOTE: Insertion *MUST* be from greatest range to least for it to work!
967c478bd9Sstevel@tonic-gate  * These should be replaced, eventually, by something else - most notably a
977c478bd9Sstevel@tonic-gate  * interval searching method.  The important feature is to be able to find
987c478bd9Sstevel@tonic-gate  * the best match.
997c478bd9Sstevel@tonic-gate  *
1007c478bd9Sstevel@tonic-gate  * So why not use a radix tree for this?  As the first line implies, it
1017c478bd9Sstevel@tonic-gate  * has been written to work with a _range_ of addresses.  A range is not
1027c478bd9Sstevel@tonic-gate  * necessarily a match with any given netmask so what we end up dealing
1037c478bd9Sstevel@tonic-gate  * with is an interval tree.  Implementations of these are hard to find
1047c478bd9Sstevel@tonic-gate  * and the one herein is far from bug free.
1057c478bd9Sstevel@tonic-gate  *
1067c478bd9Sstevel@tonic-gate  * Sigh, in the end I became convinced that the bugs the code contained did
1077c478bd9Sstevel@tonic-gate  * not make it worthwhile not using radix trees.  For now the radix tree from
1087c478bd9Sstevel@tonic-gate  * 4.4 BSD is used, but this is not viewed as a long term solution.
1097c478bd9Sstevel@tonic-gate  */
1107c478bd9Sstevel@tonic-gate 
1117c478bd9Sstevel@tonic-gate #ifdef TEST_POOL
1127c478bd9Sstevel@tonic-gate void treeprint __P((ip_pool_t *));
1137c478bd9Sstevel@tonic-gate 
1147c478bd9Sstevel@tonic-gate int
1157c478bd9Sstevel@tonic-gate main(argc, argv)
1167c478bd9Sstevel@tonic-gate 	int argc;
1177c478bd9Sstevel@tonic-gate 	char *argv[];
1187c478bd9Sstevel@tonic-gate {
1197c478bd9Sstevel@tonic-gate 	addrfamily_t a, b;
1207c478bd9Sstevel@tonic-gate 	iplookupop_t op;
1217c478bd9Sstevel@tonic-gate 	ip_pool_t *ipo;
1227c478bd9Sstevel@tonic-gate 	i6addr_t ip;
1237c478bd9Sstevel@tonic-gate 
124*f4b3ec61Sdh 	RWLOCK_INIT(&ifs->ifs_ip_poolrw, "poolrw");
125*f4b3ec61Sdh 	ip_pool_init(ifs);
1267c478bd9Sstevel@tonic-gate 
1277c478bd9Sstevel@tonic-gate 	bzero((char *)&a, sizeof(a));
1287c478bd9Sstevel@tonic-gate 	bzero((char *)&b, sizeof(b));
1297c478bd9Sstevel@tonic-gate 	bzero((char *)&ip, sizeof(ip));
1307c478bd9Sstevel@tonic-gate 	bzero((char *)&op, sizeof(op));
1317c478bd9Sstevel@tonic-gate 	strcpy(op.iplo_name, "0");
1327c478bd9Sstevel@tonic-gate 
133*f4b3ec61Sdh 	if (ip_pool_create(&op, ifs) == 0)
134*f4b3ec61Sdh 		ipo = ip_pool_find(0, "0", ifs);
1357c478bd9Sstevel@tonic-gate 
1367c478bd9Sstevel@tonic-gate 	a.adf_addr.in4.s_addr = 0x0a010203;
1377c478bd9Sstevel@tonic-gate 	b.adf_addr.in4.s_addr = 0xffffffff;
138*f4b3ec61Sdh 	ip_pool_insert(ipo, &a, &b, 1, ifs);
139*f4b3ec61Sdh 	ip_pool_insert(ipo, &a, &b, 1, ifs);
1407c478bd9Sstevel@tonic-gate 
1417c478bd9Sstevel@tonic-gate 	a.adf_addr.in4.s_addr = 0x0a000000;
1427c478bd9Sstevel@tonic-gate 	b.adf_addr.in4.s_addr = 0xff000000;
143*f4b3ec61Sdh 	ip_pool_insert(ipo, &a, &b, 0, ifs);
144*f4b3ec61Sdh 	ip_pool_insert(ipo, &a, &b, 0, ifs);
1457c478bd9Sstevel@tonic-gate 
1467c478bd9Sstevel@tonic-gate 	a.adf_addr.in4.s_addr = 0x0a010100;
1477c478bd9Sstevel@tonic-gate 	b.adf_addr.in4.s_addr = 0xffffff00;
148*f4b3ec61Sdh 	ip_pool_insert(ipo, &a, &b, 1, ifs);
149*f4b3ec61Sdh 	ip_pool_insert(ipo, &a, &b, 1, ifs);
1507c478bd9Sstevel@tonic-gate 
1517c478bd9Sstevel@tonic-gate 	a.adf_addr.in4.s_addr = 0x0a010200;
1527c478bd9Sstevel@tonic-gate 	b.adf_addr.in4.s_addr = 0xffffff00;
153*f4b3ec61Sdh 	ip_pool_insert(ipo, &a, &b, 0, ifs);
154*f4b3ec61Sdh 	ip_pool_insert(ipo, &a, &b, 0, ifs);
1557c478bd9Sstevel@tonic-gate 
1567c478bd9Sstevel@tonic-gate 	a.adf_addr.in4.s_addr = 0x0a010000;
1577c478bd9Sstevel@tonic-gate 	b.adf_addr.in4.s_addr = 0xffff0000;
158*f4b3ec61Sdh 	ip_pool_insert(ipo, &a, &b, 1, ifs);
159*f4b3ec61Sdh 	ip_pool_insert(ipo, &a, &b, 1, ifs);
1607c478bd9Sstevel@tonic-gate 
1617c478bd9Sstevel@tonic-gate 	a.adf_addr.in4.s_addr = 0x0a01020f;
1627c478bd9Sstevel@tonic-gate 	b.adf_addr.in4.s_addr = 0xffffffff;
163*f4b3ec61Sdh 	ip_pool_insert(ipo, &a, &b, 1, ifs);
164*f4b3ec61Sdh 	ip_pool_insert(ipo, &a, &b, 1, ifs);
1657c478bd9Sstevel@tonic-gate #ifdef	DEBUG_POOL
1667c478bd9Sstevel@tonic-gate treeprint(ipo);
1677c478bd9Sstevel@tonic-gate #endif
1687c478bd9Sstevel@tonic-gate 	ip.in4.s_addr = 0x0a00aabb;
1697c478bd9Sstevel@tonic-gate 	printf("search(%#x) = %d (0)\n", ip.in4.s_addr,
170*f4b3ec61Sdh 		ip_pool_search(ipo, 4, &ip, ifs));
1717c478bd9Sstevel@tonic-gate 
1727c478bd9Sstevel@tonic-gate 	ip.in4.s_addr = 0x0a000001;
1737c478bd9Sstevel@tonic-gate 	printf("search(%#x) = %d (0)\n", ip.in4.s_addr,
174*f4b3ec61Sdh 		ip_pool_search(ipo, 4, &ip, ifs));
1757c478bd9Sstevel@tonic-gate 
1767c478bd9Sstevel@tonic-gate 	ip.in4.s_addr = 0x0a000101;
1777c478bd9Sstevel@tonic-gate 	printf("search(%#x) = %d (0)\n", ip.in4.s_addr,
178*f4b3ec61Sdh 		ip_pool_search(ipo, 4, &ip, ifs));
1797c478bd9Sstevel@tonic-gate 
1807c478bd9Sstevel@tonic-gate 	ip.in4.s_addr = 0x0a010001;
1817c478bd9Sstevel@tonic-gate 	printf("search(%#x) = %d (1)\n", ip.in4.s_addr,
182*f4b3ec61Sdh 		ip_pool_search(ipo, 4, &ip, ifs));
1837c478bd9Sstevel@tonic-gate 
1847c478bd9Sstevel@tonic-gate 	ip.in4.s_addr = 0x0a010101;
1857c478bd9Sstevel@tonic-gate 	printf("search(%#x) = %d (1)\n", ip.in4.s_addr,
186*f4b3ec61Sdh 		ip_pool_search(ipo, 4, &ip, ifs));
1877c478bd9Sstevel@tonic-gate 
1887c478bd9Sstevel@tonic-gate 	ip.in4.s_addr = 0x0a010201;
1897c478bd9Sstevel@tonic-gate 	printf("search(%#x) = %d (0)\n", ip.in4.s_addr,
190*f4b3ec61Sdh 		ip_pool_search(ipo, 4, &ip, ifs));
1917c478bd9Sstevel@tonic-gate 
1927c478bd9Sstevel@tonic-gate 	ip.in4.s_addr = 0x0a010203;
1937c478bd9Sstevel@tonic-gate 	printf("search(%#x) = %d (1)\n", ip.in4.s_addr,
194*f4b3ec61Sdh 		ip_pool_search(ipo, 4, &ip, ifs));
1957c478bd9Sstevel@tonic-gate 
1967c478bd9Sstevel@tonic-gate 	ip.in4.s_addr = 0x0a01020f;
1977c478bd9Sstevel@tonic-gate 	printf("search(%#x) = %d (1)\n", ip.in4.s_addr,
198*f4b3ec61Sdh 		ip_pool_search(ipo, 4, &ip, ifs));
1997c478bd9Sstevel@tonic-gate 
2007c478bd9Sstevel@tonic-gate 	ip.in4.s_addr = 0x0b00aabb;
2017c478bd9Sstevel@tonic-gate 	printf("search(%#x) = %d (-1)\n", ip.in4.s_addr,
202*f4b3ec61Sdh 		ip_pool_search(ipo, 4, &ip, ifs));
2037c478bd9Sstevel@tonic-gate 
2047c478bd9Sstevel@tonic-gate #ifdef	DEBUG_POOL
2057c478bd9Sstevel@tonic-gate treeprint(ipo);
2067c478bd9Sstevel@tonic-gate #endif
2077c478bd9Sstevel@tonic-gate 
208*f4b3ec61Sdh 	ip_pool_fini(ifs);
2097c478bd9Sstevel@tonic-gate 
2107c478bd9Sstevel@tonic-gate 	return 0;
2117c478bd9Sstevel@tonic-gate }
2127c478bd9Sstevel@tonic-gate 
2137c478bd9Sstevel@tonic-gate 
2147c478bd9Sstevel@tonic-gate void
2157c478bd9Sstevel@tonic-gate treeprint(ipo)
2167c478bd9Sstevel@tonic-gate ip_pool_t *ipo;
2177c478bd9Sstevel@tonic-gate {
2187c478bd9Sstevel@tonic-gate 	ip_pool_node_t *c;
2197c478bd9Sstevel@tonic-gate 
2207c478bd9Sstevel@tonic-gate 	for (c = ipo->ipo_list; c != NULL; c = c->ipn_next)
2217c478bd9Sstevel@tonic-gate 		printf("Node %p(%s) (%#x/%#x) = %d hits %lu\n",
2227c478bd9Sstevel@tonic-gate 			c, c->ipn_name, c->ipn_addr.adf_addr.in4.s_addr,
2237c478bd9Sstevel@tonic-gate 			c->ipn_mask.adf_addr.in4.s_addr,
2247c478bd9Sstevel@tonic-gate 			c->ipn_info, c->ipn_hits);
2257c478bd9Sstevel@tonic-gate }
2267c478bd9Sstevel@tonic-gate #endif /* TEST_POOL */
2277c478bd9Sstevel@tonic-gate 
2287c478bd9Sstevel@tonic-gate 
2297c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */
2307c478bd9Sstevel@tonic-gate /* Function:    ip_pool_init                                                */
2317c478bd9Sstevel@tonic-gate /* Returns:     int     - 0 = success, else error                           */
2327c478bd9Sstevel@tonic-gate /*                                                                          */
2337c478bd9Sstevel@tonic-gate /* Initialise the routing table data structures where required.             */
2347c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */
235*f4b3ec61Sdh int ip_pool_init(ifs)
236*f4b3ec61Sdh ipf_stack_t *ifs;
2377c478bd9Sstevel@tonic-gate {
238ab25eeb5Syz 
239*f4b3ec61Sdh 	bzero(&ifs->ifs_ipoolstat, sizeof (ip_pool_stat_t));
2407c478bd9Sstevel@tonic-gate 
241c793af95Ssangeeta #if !defined(_KERNEL) || ((BSD < 199306) && (SOLARIS2 < 10))
2427c478bd9Sstevel@tonic-gate 	rn_init();
2437c478bd9Sstevel@tonic-gate #endif
2447c478bd9Sstevel@tonic-gate 	return 0;
2457c478bd9Sstevel@tonic-gate }
2467c478bd9Sstevel@tonic-gate 
2477c478bd9Sstevel@tonic-gate 
2487c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */
2497c478bd9Sstevel@tonic-gate /* Function:    ip_pool_fini                                                */
2507c478bd9Sstevel@tonic-gate /* Returns:     int     - 0 = success, else error                           */
2517c478bd9Sstevel@tonic-gate /* Locks:       WRITE(ipf_global)                                           */
2527c478bd9Sstevel@tonic-gate /*                                                                          */
2537c478bd9Sstevel@tonic-gate /* Clean up all the pool data structures allocated and call the cleanup     */
2547c478bd9Sstevel@tonic-gate /* function for the radix tree that supports the pools. ip_pool_destroy() is*/
2557c478bd9Sstevel@tonic-gate /* used to delete the pools one by one to ensure they're properly freed up. */
2567c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */
257*f4b3ec61Sdh void ip_pool_fini(ifs)
258*f4b3ec61Sdh ipf_stack_t *ifs;
2597c478bd9Sstevel@tonic-gate {
2607c478bd9Sstevel@tonic-gate 	ip_pool_t *p, *q;
2617c478bd9Sstevel@tonic-gate 	iplookupop_t op;
2627c478bd9Sstevel@tonic-gate 	int i;
2637c478bd9Sstevel@tonic-gate 
264*f4b3ec61Sdh 	ASSERT(rw_read_locked(&ifs->ifs_ipf_global.ipf_lk) == 0);
2657c478bd9Sstevel@tonic-gate 
2667c478bd9Sstevel@tonic-gate 	for (i = 0; i <= IPL_LOGMAX; i++) {
267*f4b3ec61Sdh 		for (q = ifs->ifs_ip_pool_list[i]; (p = q) != NULL; ) {
2687c478bd9Sstevel@tonic-gate 			op.iplo_unit = i;
2697c478bd9Sstevel@tonic-gate 			(void)strncpy(op.iplo_name, p->ipo_name,
2707c478bd9Sstevel@tonic-gate 				sizeof(op.iplo_name));
2717c478bd9Sstevel@tonic-gate 			q = p->ipo_next;
272*f4b3ec61Sdh 			(void) ip_pool_destroy(&op, ifs);
2737c478bd9Sstevel@tonic-gate 		}
2747c478bd9Sstevel@tonic-gate 	}
2757c478bd9Sstevel@tonic-gate 
276c793af95Ssangeeta #if !defined(_KERNEL) || ((BSD < 199306) && (SOLARIS2 < 10))
2777c478bd9Sstevel@tonic-gate 	rn_fini();
2787c478bd9Sstevel@tonic-gate #endif
2797c478bd9Sstevel@tonic-gate }
2807c478bd9Sstevel@tonic-gate 
281ab25eeb5Syz 
2827663b816Sml /* ------------------------------------------------------------------------ */
2837663b816Sml /* Function:    ip_pool_statistics                                          */
2847663b816Sml /* Returns:     int     - 0 = success, else error                           */
2857663b816Sml /* Parameters:  op(I)   - pointer to lookup operation arguments             */
2867663b816Sml /*                                                                          */
2877663b816Sml /* Copy the current statistics out into user space, collecting pool list    */
2887663b816Sml /* pointers as appropriate for later use.                                   */
2897663b816Sml /* ------------------------------------------------------------------------ */
290*f4b3ec61Sdh int ip_pool_statistics(op, ifs)
2917663b816Sml iplookupop_t *op;
292*f4b3ec61Sdh ipf_stack_t *ifs;
2937663b816Sml {
2947663b816Sml 	ip_pool_stat_t stats;
2957663b816Sml 	int unit, i, err = 0;
2967663b816Sml 
297*f4b3ec61Sdh 	if (op->iplo_size != sizeof(ip_pool_stat_t))
2987663b816Sml 		return EINVAL;
2997663b816Sml 
300*f4b3ec61Sdh 	bcopy((char *)&ifs->ifs_ipoolstat, (char *)&stats, sizeof(stats));
3017663b816Sml 	unit = op->iplo_unit;
3027663b816Sml 	if (unit == IPL_LOGALL) {
3037663b816Sml 		for (i = 0; i < IPL_LOGSIZE; i++)
304*f4b3ec61Sdh 			stats.ipls_list[i] = ifs->ifs_ip_pool_list[i];
3057663b816Sml 	} else if (unit >= 0 && unit < IPL_LOGSIZE) {
306ab25eeb5Syz 		if (op->iplo_name[0] != '\0')
307ab25eeb5Syz 			stats.ipls_list[unit] = ip_pool_find(unit,
308*f4b3ec61Sdh 							     op->iplo_name, ifs);
309ab25eeb5Syz 		else
310*f4b3ec61Sdh 			stats.ipls_list[unit] = ifs->ifs_ip_pool_list[unit];
3117663b816Sml 	} else
3127663b816Sml 		err = EINVAL;
3137663b816Sml 	if (err == 0)
3147663b816Sml 		err = COPYOUT(&stats, op->iplo_struct, sizeof(stats));
3157663b816Sml 	return err;
3167663b816Sml }
3177663b816Sml 
3187c478bd9Sstevel@tonic-gate 
319ab25eeb5Syz 
3207c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */
3217c478bd9Sstevel@tonic-gate /* Function:    ip_pool_find                                                */
3227c478bd9Sstevel@tonic-gate /* Returns:     int     - 0 = success, else error                           */
3237c478bd9Sstevel@tonic-gate /* Parameters:  ipo(I)  - pointer to the pool getting the new node.         */
3247c478bd9Sstevel@tonic-gate /*                                                                          */
3257c478bd9Sstevel@tonic-gate /* Find a matching pool inside the collection of pools for a particular     */
3267c478bd9Sstevel@tonic-gate /* device, indicated by the unit number.                                    */
3277c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */
328*f4b3ec61Sdh void *ip_pool_find(unit, name, ifs)
3297c478bd9Sstevel@tonic-gate int unit;
3307c478bd9Sstevel@tonic-gate char *name;
331*f4b3ec61Sdh ipf_stack_t *ifs;
3327c478bd9Sstevel@tonic-gate {
3337c478bd9Sstevel@tonic-gate 	ip_pool_t *p;
3347c478bd9Sstevel@tonic-gate 
335*f4b3ec61Sdh 	for (p = ifs->ifs_ip_pool_list[unit]; p != NULL; p = p->ipo_next)
336ab25eeb5Syz 		if (strncmp(p->ipo_name, name, sizeof(p->ipo_name)) == 0)
3377c478bd9Sstevel@tonic-gate 			break;
3387c478bd9Sstevel@tonic-gate 	return p;
3397c478bd9Sstevel@tonic-gate }
3407c478bd9Sstevel@tonic-gate 
3417c478bd9Sstevel@tonic-gate 
3427c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */
3437c478bd9Sstevel@tonic-gate /* Function:    ip_pool_findeq                                              */
3447c478bd9Sstevel@tonic-gate /* Returns:     int     - 0 = success, else error                           */
3457c478bd9Sstevel@tonic-gate /* Parameters:  ipo(I)  - pointer to the pool getting the new node.         */
346ab25eeb5Syz /*              addr(I) - pointer to address information to delete          */
3477c478bd9Sstevel@tonic-gate /*              mask(I) -                                                   */
3487c478bd9Sstevel@tonic-gate /*                                                                          */
3497c478bd9Sstevel@tonic-gate /* Searches for an exact match of an entry in the pool.                     */
3507c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */
3517c478bd9Sstevel@tonic-gate ip_pool_node_t *ip_pool_findeq(ipo, addr, mask)
3527c478bd9Sstevel@tonic-gate ip_pool_t *ipo;
3537663b816Sml addrfamily_t *addr, *mask;
3547c478bd9Sstevel@tonic-gate {
3557c478bd9Sstevel@tonic-gate 	struct radix_node *n;
356ab25eeb5Syz 	SPL_INT(s);
3577c478bd9Sstevel@tonic-gate 
358ab25eeb5Syz 	SPL_NET(s);
3597c478bd9Sstevel@tonic-gate 	n = ipo->ipo_head->rnh_lookup(addr, mask, ipo->ipo_head);
360ab25eeb5Syz 	SPL_X(s);
3617c478bd9Sstevel@tonic-gate 	return (ip_pool_node_t *)n;
3627c478bd9Sstevel@tonic-gate }
3637c478bd9Sstevel@tonic-gate 
3647c478bd9Sstevel@tonic-gate 
3657c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */
3667c478bd9Sstevel@tonic-gate /* Function:    ip_pool_search                                              */
367ab25eeb5Syz /* Returns:     int     - 0 == +ve match, -1 == error, 1 == -ve/no match    */
3687c478bd9Sstevel@tonic-gate /* Parameters:  tptr(I)    - pointer to the pool to search                  */
3697c478bd9Sstevel@tonic-gate /*              version(I) - IP protocol version (4 or 6)                   */
3707c478bd9Sstevel@tonic-gate /*              dptr(I)    - pointer to address information                 */
3717c478bd9Sstevel@tonic-gate /*                                                                          */
3727c478bd9Sstevel@tonic-gate /* Search the pool for a given address and return a search result.          */
3737c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */
374*f4b3ec61Sdh int ip_pool_search(tptr, version, dptr, ifs)
3757c478bd9Sstevel@tonic-gate void *tptr;
3767c478bd9Sstevel@tonic-gate int version;
3777c478bd9Sstevel@tonic-gate void *dptr;
378*f4b3ec61Sdh ipf_stack_t *ifs;
3797c478bd9Sstevel@tonic-gate {
3807c478bd9Sstevel@tonic-gate 	struct radix_node *rn;
3817c478bd9Sstevel@tonic-gate 	ip_pool_node_t *m;
3827c478bd9Sstevel@tonic-gate 	i6addr_t *addr;
3837c478bd9Sstevel@tonic-gate 	addrfamily_t v;
3847c478bd9Sstevel@tonic-gate 	ip_pool_t *ipo;
3857c478bd9Sstevel@tonic-gate 	int rv;
3867c478bd9Sstevel@tonic-gate 
3877c478bd9Sstevel@tonic-gate 	ipo = tptr;
3887c478bd9Sstevel@tonic-gate 	if (ipo == NULL)
3897c478bd9Sstevel@tonic-gate 		return -1;
3907c478bd9Sstevel@tonic-gate 
3917c478bd9Sstevel@tonic-gate 	rv = 1;
3927c478bd9Sstevel@tonic-gate 	m = NULL;
3937c478bd9Sstevel@tonic-gate 	addr = (i6addr_t *)dptr;
3947c478bd9Sstevel@tonic-gate 	bzero(&v, sizeof(v));
3957c478bd9Sstevel@tonic-gate 	v.adf_len = offsetof(addrfamily_t, adf_addr);
3967c478bd9Sstevel@tonic-gate 
3977c478bd9Sstevel@tonic-gate 	if (version == 4) {
3987c478bd9Sstevel@tonic-gate 		v.adf_len += sizeof(addr->in4);
3997c478bd9Sstevel@tonic-gate 		v.adf_addr.in4 = addr->in4;
4007c478bd9Sstevel@tonic-gate #ifdef USE_INET6
4017c478bd9Sstevel@tonic-gate 	} else if (version == 6) {
4027c478bd9Sstevel@tonic-gate 		v.adf_len += sizeof(addr->in6);
4037c478bd9Sstevel@tonic-gate 		v.adf_addr.in6 = addr->in6;
4047c478bd9Sstevel@tonic-gate #endif
4057c478bd9Sstevel@tonic-gate 	} else
4067c478bd9Sstevel@tonic-gate 		return -1;
4077c478bd9Sstevel@tonic-gate 
408*f4b3ec61Sdh 	READ_ENTER(&ifs->ifs_ip_poolrw);
4097c478bd9Sstevel@tonic-gate 
4107c478bd9Sstevel@tonic-gate 	rn = ipo->ipo_head->rnh_matchaddr(&v, ipo->ipo_head);
4117c478bd9Sstevel@tonic-gate 
4127c478bd9Sstevel@tonic-gate 	if ((rn != NULL) && ((rn->rn_flags & RNF_ROOT) == 0)) {
4137c478bd9Sstevel@tonic-gate 		m = (ip_pool_node_t *)rn;
4147c478bd9Sstevel@tonic-gate 		ipo->ipo_hits++;
4157c478bd9Sstevel@tonic-gate 		m->ipn_hits++;
4167c478bd9Sstevel@tonic-gate 		rv = m->ipn_info;
4177c478bd9Sstevel@tonic-gate 	}
418*f4b3ec61Sdh 	RWLOCK_EXIT(&ifs->ifs_ip_poolrw);
4197c478bd9Sstevel@tonic-gate 	return rv;
4207c478bd9Sstevel@tonic-gate }
4217c478bd9Sstevel@tonic-gate 
4227c478bd9Sstevel@tonic-gate 
4237c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */
4247c478bd9Sstevel@tonic-gate /* Function:    ip_pool_insert                                              */
4257c478bd9Sstevel@tonic-gate /* Returns:     int     - 0 = success, else error                           */
4267c478bd9Sstevel@tonic-gate /* Parameters:  ipo(I)  - pointer to the pool getting the new node.         */
4277663b816Sml /*              addr(I) - IPv4/6 address being added as a node              */
4287663b816Sml /*              mask(I) - IPv4/6 netmask to with the node being added       */
4297c478bd9Sstevel@tonic-gate /*              info(I) - extra information to store in this node.          */
4307c478bd9Sstevel@tonic-gate /* Locks:       WRITE(ip_poolrw)                                            */
4317c478bd9Sstevel@tonic-gate /*                                                                          */
4327c478bd9Sstevel@tonic-gate /* Add another node to the pool given by ipo.  The three parameters passed  */
4337c478bd9Sstevel@tonic-gate /* in (addr, mask, info) shold all be stored in the node.                   */
4347c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */
435*f4b3ec61Sdh int ip_pool_insert(ipo, addr, mask, info, ifs)
4367c478bd9Sstevel@tonic-gate ip_pool_t *ipo;
4377663b816Sml addrfamily_t *addr, *mask;
4387c478bd9Sstevel@tonic-gate int info;
439*f4b3ec61Sdh ipf_stack_t *ifs;
4407c478bd9Sstevel@tonic-gate {
4417c478bd9Sstevel@tonic-gate 	struct radix_node *rn;
4427c478bd9Sstevel@tonic-gate 	ip_pool_node_t *x;
4437c478bd9Sstevel@tonic-gate 
444*f4b3ec61Sdh 	ASSERT(rw_read_locked(&ifs->ifs_ip_poolrw.ipf_lk) == 0);
4457c478bd9Sstevel@tonic-gate 
4467c478bd9Sstevel@tonic-gate 	KMALLOC(x, ip_pool_node_t *);
4477c478bd9Sstevel@tonic-gate 	if (x == NULL) {
4487c478bd9Sstevel@tonic-gate 		return ENOMEM;
4497c478bd9Sstevel@tonic-gate 	}
4507c478bd9Sstevel@tonic-gate 
4517c478bd9Sstevel@tonic-gate 	bzero(x, sizeof(*x));
4527c478bd9Sstevel@tonic-gate 
4537c478bd9Sstevel@tonic-gate 	x->ipn_info = info;
4547c478bd9Sstevel@tonic-gate 	(void)strncpy(x->ipn_name, ipo->ipo_name, sizeof(x->ipn_name));
4557c478bd9Sstevel@tonic-gate 
4567663b816Sml 	bcopy(addr, &x->ipn_addr, sizeof(*addr));
4577c478bd9Sstevel@tonic-gate 	x->ipn_addr.adf_len = sizeof(x->ipn_addr);
4587663b816Sml 	bcopy(mask, &x->ipn_mask, sizeof(*mask));
4597c478bd9Sstevel@tonic-gate 	x->ipn_mask.adf_len = sizeof(x->ipn_mask);
4607c478bd9Sstevel@tonic-gate 
4617c478bd9Sstevel@tonic-gate 	rn = ipo->ipo_head->rnh_addaddr(&x->ipn_addr, &x->ipn_mask,
4627c478bd9Sstevel@tonic-gate 					ipo->ipo_head, x->ipn_nodes);
4637c478bd9Sstevel@tonic-gate #ifdef	DEBUG_POOL
4647c478bd9Sstevel@tonic-gate 	printf("Added %p at %p\n", x, rn);
4657c478bd9Sstevel@tonic-gate #endif
4667c478bd9Sstevel@tonic-gate 
4677c478bd9Sstevel@tonic-gate 	if (rn == NULL) {
4687c478bd9Sstevel@tonic-gate 		KFREE(x);
4697c478bd9Sstevel@tonic-gate 		return ENOMEM;
4707c478bd9Sstevel@tonic-gate 	}
4717c478bd9Sstevel@tonic-gate 
472*f4b3ec61Sdh 	x->ipn_ref = 1;
4737c478bd9Sstevel@tonic-gate 	x->ipn_next = ipo->ipo_list;
4747c478bd9Sstevel@tonic-gate 	x->ipn_pnext = &ipo->ipo_list;
4757c478bd9Sstevel@tonic-gate 	if (ipo->ipo_list != NULL)
4767c478bd9Sstevel@tonic-gate 		ipo->ipo_list->ipn_pnext = &x->ipn_next;
4777c478bd9Sstevel@tonic-gate 	ipo->ipo_list = x;
4787c478bd9Sstevel@tonic-gate 
479*f4b3ec61Sdh 	ifs->ifs_ipoolstat.ipls_nodes++;
48008254dd3Syz 
4817c478bd9Sstevel@tonic-gate 	return 0;
4827c478bd9Sstevel@tonic-gate }
4837c478bd9Sstevel@tonic-gate 
4847c478bd9Sstevel@tonic-gate 
4857c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */
4867c478bd9Sstevel@tonic-gate /* Function:    ip_pool_create                                              */
4877c478bd9Sstevel@tonic-gate /* Returns:     int     - 0 = success, else error                           */
4887c478bd9Sstevel@tonic-gate /* Parameters:  op(I) - pointer to iplookup struct with call details        */
4897c478bd9Sstevel@tonic-gate /* Locks:       WRITE(ip_poolrw)                                            */
4907c478bd9Sstevel@tonic-gate /*                                                                          */
4917c478bd9Sstevel@tonic-gate /* Creates a new group according to the paramters passed in via the         */
4927c478bd9Sstevel@tonic-gate /* iplookupop structure.  Does not check to see if the group already exists */
4937c478bd9Sstevel@tonic-gate /* when being inserted - assume this has already been done.  If the pool is */
4947c478bd9Sstevel@tonic-gate /* marked as being anonymous, give it a new, unique, identifier.  Call any  */
4957c478bd9Sstevel@tonic-gate /* other functions required to initialise the structure.                    */
4967c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */
497*f4b3ec61Sdh int ip_pool_create(op, ifs)
4987c478bd9Sstevel@tonic-gate iplookupop_t *op;
499*f4b3ec61Sdh ipf_stack_t *ifs;
5007c478bd9Sstevel@tonic-gate {
5017c478bd9Sstevel@tonic-gate 	char name[FR_GROUPLEN];
5027c478bd9Sstevel@tonic-gate 	int poolnum, unit;
5037c478bd9Sstevel@tonic-gate 	ip_pool_t *h;
5047c478bd9Sstevel@tonic-gate 
505*f4b3ec61Sdh 	ASSERT(rw_read_locked(&ifs->ifs_ip_poolrw.ipf_lk) == 0);
5067c478bd9Sstevel@tonic-gate 
5077c478bd9Sstevel@tonic-gate 	KMALLOC(h, ip_pool_t *);
5087c478bd9Sstevel@tonic-gate 	if (h == NULL)
5097c478bd9Sstevel@tonic-gate 		return ENOMEM;
5107c478bd9Sstevel@tonic-gate 	bzero(h, sizeof(*h));
5117c478bd9Sstevel@tonic-gate 
5127c478bd9Sstevel@tonic-gate 	if (rn_inithead((void **)&h->ipo_head,
5137c478bd9Sstevel@tonic-gate 			offsetof(addrfamily_t, adf_addr) << 3) == 0) {
5147c478bd9Sstevel@tonic-gate 		KFREE(h);
5157c478bd9Sstevel@tonic-gate 		return ENOMEM;
5167c478bd9Sstevel@tonic-gate 	}
5177c478bd9Sstevel@tonic-gate 
5187c478bd9Sstevel@tonic-gate 	unit = op->iplo_unit;
5197c478bd9Sstevel@tonic-gate 
5207c478bd9Sstevel@tonic-gate 	if ((op->iplo_arg & IPOOL_ANON) != 0) {
5217c478bd9Sstevel@tonic-gate 		ip_pool_t *p;
5227c478bd9Sstevel@tonic-gate 
5237c478bd9Sstevel@tonic-gate 		poolnum = IPOOL_ANON;
524ab25eeb5Syz 
525ab25eeb5Syz #if defined(SNPRINTF) && defined(_KERNEL)
526ab25eeb5Syz 		(void)SNPRINTF(name, sizeof(name), "%x", poolnum);
527ab25eeb5Syz #else
5287c478bd9Sstevel@tonic-gate 		(void)sprintf(name, "%x", poolnum);
529ab25eeb5Syz #endif
530ab25eeb5Syz 
531*f4b3ec61Sdh 		for (p = ifs->ifs_ip_pool_list[unit]; p != NULL; ) {
532ab25eeb5Syz 			if (strncmp(name, p->ipo_name,
533ab25eeb5Syz 				    sizeof(p->ipo_name)) == 0) {
5347c478bd9Sstevel@tonic-gate 				poolnum++;
535ab25eeb5Syz #if defined(SNPRINTF) && defined(_KERNEL)
536ab25eeb5Syz 				(void)SNPRINTF(name, sizeof(name), "%x", poolnum);
537ab25eeb5Syz #else
5387c478bd9Sstevel@tonic-gate 				(void)sprintf(name, "%x", poolnum);
539ab25eeb5Syz #endif
540*f4b3ec61Sdh 				p = ifs->ifs_ip_pool_list[unit];
5417c478bd9Sstevel@tonic-gate 			} else
5427c478bd9Sstevel@tonic-gate 				p = p->ipo_next;
5437c478bd9Sstevel@tonic-gate 		}
5447c478bd9Sstevel@tonic-gate 
5457c478bd9Sstevel@tonic-gate 		(void)strncpy(h->ipo_name, name, sizeof(h->ipo_name));
5467c478bd9Sstevel@tonic-gate 	} else {
5477c478bd9Sstevel@tonic-gate 		(void) strncpy(h->ipo_name, op->iplo_name, sizeof(h->ipo_name));
5487c478bd9Sstevel@tonic-gate 	}
5497c478bd9Sstevel@tonic-gate 
5507c478bd9Sstevel@tonic-gate 	h->ipo_ref = 1;
5517c478bd9Sstevel@tonic-gate 	h->ipo_list = NULL;
5527c478bd9Sstevel@tonic-gate 	h->ipo_unit = unit;
553*f4b3ec61Sdh 	h->ipo_next = ifs->ifs_ip_pool_list[unit];
554*f4b3ec61Sdh 	if (ifs->ifs_ip_pool_list[unit] != NULL)
555*f4b3ec61Sdh 		ifs->ifs_ip_pool_list[unit]->ipo_pnext = &h->ipo_next;
556*f4b3ec61Sdh 	h->ipo_pnext = &ifs->ifs_ip_pool_list[unit];
557*f4b3ec61Sdh 	ifs->ifs_ip_pool_list[unit] = h;
55808254dd3Syz 
559*f4b3ec61Sdh 	ifs->ifs_ipoolstat.ipls_pools++;
56008254dd3Syz 
5617c478bd9Sstevel@tonic-gate 	return 0;
5627c478bd9Sstevel@tonic-gate }
5637c478bd9Sstevel@tonic-gate 
5647c478bd9Sstevel@tonic-gate 
5657c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */
5667c478bd9Sstevel@tonic-gate /* Function:    ip_pool_remove                                              */
5677c478bd9Sstevel@tonic-gate /* Returns:     int    - 0 = success, else error                            */
5687c478bd9Sstevel@tonic-gate /* Parameters:  ipo(I) - pointer to the pool to remove the node from.       */
5697c478bd9Sstevel@tonic-gate /*              ipe(I) - address being deleted as a node                    */
5707c478bd9Sstevel@tonic-gate /* Locks:       WRITE(ip_poolrw)                                            */
5717c478bd9Sstevel@tonic-gate /*                                                                          */
5727c478bd9Sstevel@tonic-gate /* Add another node to the pool given by ipo.  The three parameters passed  */
5737c478bd9Sstevel@tonic-gate /* in (addr, mask, info) shold all be stored in the node.                   */
5747c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */
575*f4b3ec61Sdh int ip_pool_remove(ipo, ipe, ifs)
5767c478bd9Sstevel@tonic-gate ip_pool_t *ipo;
5777c478bd9Sstevel@tonic-gate ip_pool_node_t *ipe;
578*f4b3ec61Sdh ipf_stack_t *ifs;
5797c478bd9Sstevel@tonic-gate {
5807c478bd9Sstevel@tonic-gate 	ip_pool_node_t **ipp, *n;
5817c478bd9Sstevel@tonic-gate 
582*f4b3ec61Sdh 	ASSERT(rw_read_locked(&ifs->ifs_ip_poolrw.ipf_lk) == 0);
5837c478bd9Sstevel@tonic-gate 
5847c478bd9Sstevel@tonic-gate 	for (ipp = &ipo->ipo_list; (n = *ipp) != NULL; ipp = &n->ipn_next) {
5857c478bd9Sstevel@tonic-gate 		if (ipe == n) {
5867c478bd9Sstevel@tonic-gate 			*n->ipn_pnext = n->ipn_next;
5877c478bd9Sstevel@tonic-gate 			if (n->ipn_next)
5887c478bd9Sstevel@tonic-gate 				n->ipn_next->ipn_pnext = n->ipn_pnext;
5897c478bd9Sstevel@tonic-gate 			break;
5907c478bd9Sstevel@tonic-gate 		}
5917c478bd9Sstevel@tonic-gate 	}
5927c478bd9Sstevel@tonic-gate 
5937c478bd9Sstevel@tonic-gate 	if (n == NULL)
5947c478bd9Sstevel@tonic-gate 		return ENOENT;
5957c478bd9Sstevel@tonic-gate 
5967c478bd9Sstevel@tonic-gate 	ipo->ipo_head->rnh_deladdr(&n->ipn_addr, &n->ipn_mask,
5977c478bd9Sstevel@tonic-gate 				   ipo->ipo_head);
5987c478bd9Sstevel@tonic-gate 	KFREE(n);
59908254dd3Syz 
600*f4b3ec61Sdh 	ifs->ifs_ipoolstat.ipls_nodes--;
60108254dd3Syz 
6027c478bd9Sstevel@tonic-gate 	return 0;
6037c478bd9Sstevel@tonic-gate }
6047c478bd9Sstevel@tonic-gate 
6057c478bd9Sstevel@tonic-gate 
6067c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */
6077c478bd9Sstevel@tonic-gate /* Function:    ip_pool_destroy                                             */
6087c478bd9Sstevel@tonic-gate /* Returns:     int    - 0 = success, else error                            */
6097c478bd9Sstevel@tonic-gate /* Parameters:  op(I)  -  information about the pool to remove              */
6107c478bd9Sstevel@tonic-gate /* Locks:       WRITE(ip_poolrw) or WRITE(ipf_global)                       */
6117c478bd9Sstevel@tonic-gate /*                                                                          */
6127c478bd9Sstevel@tonic-gate /* Search for a pool using paramters passed in and if it's not otherwise    */
6137c478bd9Sstevel@tonic-gate /* busy, free it.                                                           */
6147c478bd9Sstevel@tonic-gate /*                                                                          */
6157c478bd9Sstevel@tonic-gate /* NOTE: Because this function is called out of ipldetach() where ip_poolrw */
6167c478bd9Sstevel@tonic-gate /* may not be initialised, we can't use an ASSERT to enforce the locking    */
6177c478bd9Sstevel@tonic-gate /* assertion that one of the two (ip_poolrw,ipf_global) is held.            */
6187c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */
619*f4b3ec61Sdh int ip_pool_destroy(op, ifs)
6207c478bd9Sstevel@tonic-gate iplookupop_t *op;
621*f4b3ec61Sdh ipf_stack_t *ifs;
6227c478bd9Sstevel@tonic-gate {
6237c478bd9Sstevel@tonic-gate 	ip_pool_t *ipo;
6247c478bd9Sstevel@tonic-gate 
625*f4b3ec61Sdh 	ipo = ip_pool_find(op->iplo_unit, op->iplo_name, ifs);
6267c478bd9Sstevel@tonic-gate 	if (ipo == NULL)
6277c478bd9Sstevel@tonic-gate 		return ESRCH;
6287c478bd9Sstevel@tonic-gate 
6297c478bd9Sstevel@tonic-gate 	if (ipo->ipo_ref != 1)
6307c478bd9Sstevel@tonic-gate 		return EBUSY;
6317c478bd9Sstevel@tonic-gate 
632*f4b3ec61Sdh 	ip_pool_free(ipo, ifs);
6337c478bd9Sstevel@tonic-gate 	return 0;
6347c478bd9Sstevel@tonic-gate }
6357c478bd9Sstevel@tonic-gate 
6367c478bd9Sstevel@tonic-gate 
637ab25eeb5Syz /* ------------------------------------------------------------------------ */
638ab25eeb5Syz /* Function:    ip_pool_flush                                               */
639ab25eeb5Syz /* Returns:     int    - number of pools deleted                            */
640ab25eeb5Syz /* Parameters:  fp(I)  - which pool(s) to flush                             */
641ab25eeb5Syz /* Locks:       WRITE(ip_poolrw) or WRITE(ipf_global)                       */
642ab25eeb5Syz /*                                                                          */
643ab25eeb5Syz /* Free all pools associated with the device that matches the unit number   */
644ab25eeb5Syz /* passed in with operation.                                                */
645ab25eeb5Syz /*                                                                          */
646ab25eeb5Syz /* NOTE: Because this function is called out of ipldetach() where ip_poolrw */
647ab25eeb5Syz /* may not be initialised, we can't use an ASSERT to enforce the locking    */
648ab25eeb5Syz /* assertion that one of the two (ip_poolrw,ipf_global) is held.            */
649ab25eeb5Syz /* ------------------------------------------------------------------------ */
650*f4b3ec61Sdh int ip_pool_flush(fp, ifs)
651ab25eeb5Syz iplookupflush_t *fp;
652*f4b3ec61Sdh ipf_stack_t *ifs;
653ab25eeb5Syz {
654ab25eeb5Syz 	int i, num = 0, unit, err;
655ab25eeb5Syz 	ip_pool_t *p, *q;
656ab25eeb5Syz 	iplookupop_t op;
657ab25eeb5Syz 
658ab25eeb5Syz 	unit = fp->iplf_unit;
659ab25eeb5Syz 
660ab25eeb5Syz 	for (i = 0; i <= IPL_LOGMAX; i++) {
661ab25eeb5Syz 		if (unit != IPLT_ALL && i != unit)
662ab25eeb5Syz 			continue;
663*f4b3ec61Sdh 		for (q = ifs->ifs_ip_pool_list[i]; (p = q) != NULL; ) {
664ab25eeb5Syz 			op.iplo_unit = i;
665ab25eeb5Syz 			(void)strncpy(op.iplo_name, p->ipo_name,
666ab25eeb5Syz 				sizeof(op.iplo_name));
667ab25eeb5Syz 			q = p->ipo_next;
668*f4b3ec61Sdh 			err = ip_pool_destroy(&op, ifs);
669ab25eeb5Syz 			if (err == 0)
670ab25eeb5Syz 				num++;
671ab25eeb5Syz 			else
672ab25eeb5Syz 				break;
673ab25eeb5Syz 		}
674ab25eeb5Syz 	}
675ab25eeb5Syz 	return num;
676ab25eeb5Syz }
677ab25eeb5Syz 
678ab25eeb5Syz 
6797c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */
6807c478bd9Sstevel@tonic-gate /* Function:    ip_pool_free                                                */
6817c478bd9Sstevel@tonic-gate /* Returns:     void                                                        */
6827c478bd9Sstevel@tonic-gate /* Parameters:  ipo(I) -  pointer to pool structure                         */
6837c478bd9Sstevel@tonic-gate /* Locks:       WRITE(ip_poolrw) or WRITE(ipf_global)                       */
6847c478bd9Sstevel@tonic-gate /*                                                                          */
6857c478bd9Sstevel@tonic-gate /* Deletes the pool strucutre passed in from the list of pools and deletes  */
6867c478bd9Sstevel@tonic-gate /* all of the address information stored in it, including any tree data     */
6877c478bd9Sstevel@tonic-gate /* structures also allocated.                                               */
6887c478bd9Sstevel@tonic-gate /*                                                                          */
6897c478bd9Sstevel@tonic-gate /* NOTE: Because this function is called out of ipldetach() where ip_poolrw */
6907c478bd9Sstevel@tonic-gate /* may not be initialised, we can't use an ASSERT to enforce the locking    */
6917c478bd9Sstevel@tonic-gate /* assertion that one of the two (ip_poolrw,ipf_global) is held.            */
6927c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */
693*f4b3ec61Sdh void ip_pool_free(ipo, ifs)
6947c478bd9Sstevel@tonic-gate ip_pool_t *ipo;
695*f4b3ec61Sdh ipf_stack_t *ifs;
6967c478bd9Sstevel@tonic-gate {
6977c478bd9Sstevel@tonic-gate 	ip_pool_node_t *n;
6987c478bd9Sstevel@tonic-gate 
6997c478bd9Sstevel@tonic-gate 	while ((n = ipo->ipo_list) != NULL) {
7007c478bd9Sstevel@tonic-gate 		ipo->ipo_head->rnh_deladdr(&n->ipn_addr, &n->ipn_mask,
7017c478bd9Sstevel@tonic-gate 					   ipo->ipo_head);
702ab25eeb5Syz 
7037c478bd9Sstevel@tonic-gate 		*n->ipn_pnext = n->ipn_next;
7047c478bd9Sstevel@tonic-gate 		if (n->ipn_next)
7057c478bd9Sstevel@tonic-gate 			n->ipn_next->ipn_pnext = n->ipn_pnext;
706ab25eeb5Syz 
7077c478bd9Sstevel@tonic-gate 		KFREE(n);
70808254dd3Syz 
709*f4b3ec61Sdh 		ifs->ifs_ipoolstat.ipls_nodes--;
7107c478bd9Sstevel@tonic-gate 	}
7117c478bd9Sstevel@tonic-gate 
7127c478bd9Sstevel@tonic-gate 	ipo->ipo_list = NULL;
7137c478bd9Sstevel@tonic-gate 	if (ipo->ipo_next != NULL)
7147c478bd9Sstevel@tonic-gate 		ipo->ipo_next->ipo_pnext = ipo->ipo_pnext;
7157c478bd9Sstevel@tonic-gate 	*ipo->ipo_pnext = ipo->ipo_next;
7167c478bd9Sstevel@tonic-gate 	rn_freehead(ipo->ipo_head);
7177c478bd9Sstevel@tonic-gate 	KFREE(ipo);
71808254dd3Syz 
719*f4b3ec61Sdh 	ifs->ifs_ipoolstat.ipls_pools--;
7207c478bd9Sstevel@tonic-gate }
7217c478bd9Sstevel@tonic-gate 
7227c478bd9Sstevel@tonic-gate 
7237c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */
7247c478bd9Sstevel@tonic-gate /* Function:    ip_pool_deref                                               */
7257c478bd9Sstevel@tonic-gate /* Returns:     void                                                        */
7267c478bd9Sstevel@tonic-gate /* Parameters:  ipo(I) -  pointer to pool structure                         */
7277c478bd9Sstevel@tonic-gate /* Locks:       WRITE(ip_poolrw)                                            */
7287c478bd9Sstevel@tonic-gate /*                                                                          */
7297c478bd9Sstevel@tonic-gate /* Drop the number of known references to this pool structure by one and if */
7307c478bd9Sstevel@tonic-gate /* we arrive at zero known references, free it.                             */
7317c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */
732*f4b3ec61Sdh void ip_pool_deref(ipo, ifs)
7337c478bd9Sstevel@tonic-gate ip_pool_t *ipo;
734*f4b3ec61Sdh ipf_stack_t *ifs;
7357c478bd9Sstevel@tonic-gate {
7367c478bd9Sstevel@tonic-gate 
737*f4b3ec61Sdh 	ASSERT(rw_read_locked(&ifs->ifs_ip_poolrw.ipf_lk) == 0);
7387c478bd9Sstevel@tonic-gate 
7397c478bd9Sstevel@tonic-gate 	ipo->ipo_ref--;
7407c478bd9Sstevel@tonic-gate 	if (ipo->ipo_ref == 0)
741*f4b3ec61Sdh 		ip_pool_free(ipo, ifs);
742*f4b3ec61Sdh }
743*f4b3ec61Sdh 
744*f4b3ec61Sdh 
745*f4b3ec61Sdh 
746*f4b3ec61Sdh void ip_pool_node_deref(ipn, ifs)
747*f4b3ec61Sdh ip_pool_node_t *ipn;
748*f4b3ec61Sdh ipf_stack_t *ifs;
749*f4b3ec61Sdh {
750*f4b3ec61Sdh 
751*f4b3ec61Sdh 	ipn->ipn_ref--;
752*f4b3ec61Sdh 
753*f4b3ec61Sdh 	if (ipn->ipn_ref == 0) {
754*f4b3ec61Sdh 		KFREE(ipn);
755*f4b3ec61Sdh 		ifs->ifs_ipoolstat.ipls_nodes--;
756*f4b3ec61Sdh 	}
757*f4b3ec61Sdh }
758*f4b3ec61Sdh 
759*f4b3ec61Sdh 
760*f4b3ec61Sdh int ip_pool_getnext(token, ilp, ifs)
761*f4b3ec61Sdh ipftoken_t *token;
762*f4b3ec61Sdh ipflookupiter_t *ilp;
763*f4b3ec61Sdh ipf_stack_t *ifs;
764*f4b3ec61Sdh {
765*f4b3ec61Sdh 	ip_pool_node_t *node, zn, *nextnode;
766*f4b3ec61Sdh 	ip_pool_t *ipo, zp, *nextipo;
767*f4b3ec61Sdh 	int err;
768*f4b3ec61Sdh 
769*f4b3ec61Sdh 	err = 0;
770*f4b3ec61Sdh 	node = NULL;
771*f4b3ec61Sdh 	nextnode = NULL;
772*f4b3ec61Sdh 	ipo = NULL;
773*f4b3ec61Sdh 	nextipo = NULL;
774*f4b3ec61Sdh 
775*f4b3ec61Sdh 	READ_ENTER(&ifs->ifs_ip_poolrw);
776*f4b3ec61Sdh 
777*f4b3ec61Sdh 	switch (ilp->ili_otype)
778*f4b3ec61Sdh 	{
779*f4b3ec61Sdh 	case IPFLOOKUPITER_LIST :
780*f4b3ec61Sdh 		ipo = token->ipt_data;
781*f4b3ec61Sdh 		if (ipo == NULL) {
782*f4b3ec61Sdh 			nextipo = ifs->ifs_ip_pool_list[(int)ilp->ili_unit];
783*f4b3ec61Sdh 		} else {
784*f4b3ec61Sdh 			nextipo = ipo->ipo_next;
785*f4b3ec61Sdh 		}
786*f4b3ec61Sdh 
787*f4b3ec61Sdh 		if (nextipo != NULL) {
788*f4b3ec61Sdh 			if (nextipo->ipo_next == NULL)
789*f4b3ec61Sdh 				token->ipt_alive = 0;
790*f4b3ec61Sdh 			else {
791*f4b3ec61Sdh 				ATOMIC_INC(nextipo->ipo_ref);
792*f4b3ec61Sdh 			}
793*f4b3ec61Sdh 		} else {
794*f4b3ec61Sdh 			bzero((char *)&zp, sizeof(zp));
795*f4b3ec61Sdh 			nextipo = &zp;
796*f4b3ec61Sdh 		}
797*f4b3ec61Sdh 		break;
798*f4b3ec61Sdh 
799*f4b3ec61Sdh 	case IPFLOOKUPITER_NODE :
800*f4b3ec61Sdh 		node = token->ipt_data;
801*f4b3ec61Sdh 		if (node == NULL) {
802*f4b3ec61Sdh 			ipo = ip_pool_find(ilp->ili_unit, ilp->ili_name, ifs);
803*f4b3ec61Sdh 			if (ipo == NULL)
804*f4b3ec61Sdh 				err = ESRCH;
805*f4b3ec61Sdh 			else {
806*f4b3ec61Sdh 				nextnode = ipo->ipo_list;
807*f4b3ec61Sdh 				ipo = NULL;
808*f4b3ec61Sdh 			}
809*f4b3ec61Sdh 		} else {
810*f4b3ec61Sdh 			nextnode = node->ipn_next;
811*f4b3ec61Sdh 		}
812*f4b3ec61Sdh 
813*f4b3ec61Sdh 		if (nextnode != NULL) {
814*f4b3ec61Sdh 			if (nextnode->ipn_next == NULL)
815*f4b3ec61Sdh 				token->ipt_alive = 0;
816*f4b3ec61Sdh 			else {
817*f4b3ec61Sdh 				ATOMIC_INC(nextnode->ipn_ref);
818*f4b3ec61Sdh 			}
819*f4b3ec61Sdh 		} else {
820*f4b3ec61Sdh 			bzero((char *)&zn, sizeof(zn));
821*f4b3ec61Sdh 			nextnode = &zn;
822*f4b3ec61Sdh 		}
823*f4b3ec61Sdh 		break;
824*f4b3ec61Sdh 	default :
825*f4b3ec61Sdh 		err = EINVAL;
826*f4b3ec61Sdh 		break;
827*f4b3ec61Sdh 	}
828*f4b3ec61Sdh 
829*f4b3ec61Sdh 	RWLOCK_EXIT(&ifs->ifs_ip_poolrw);
830*f4b3ec61Sdh 
831*f4b3ec61Sdh 	if (err != 0)
832*f4b3ec61Sdh 		return err;
833*f4b3ec61Sdh 
834*f4b3ec61Sdh 	switch (ilp->ili_otype)
835*f4b3ec61Sdh 	{
836*f4b3ec61Sdh 	case IPFLOOKUPITER_LIST :
837*f4b3ec61Sdh 		if (ipo != NULL) {
838*f4b3ec61Sdh 			WRITE_ENTER(&ifs->ifs_ip_poolrw);
839*f4b3ec61Sdh 			ip_pool_deref(ipo, ifs);
840*f4b3ec61Sdh 			RWLOCK_EXIT(&ifs->ifs_ip_poolrw);
841*f4b3ec61Sdh 		}
842*f4b3ec61Sdh 		token->ipt_data = nextipo;
843*f4b3ec61Sdh 		err = COPYOUT(nextipo, ilp->ili_data, sizeof(*nextipo));
844*f4b3ec61Sdh 		if (err != 0)
845*f4b3ec61Sdh 			err = EFAULT;
846*f4b3ec61Sdh 		break;
847*f4b3ec61Sdh 
848*f4b3ec61Sdh 	case IPFLOOKUPITER_NODE :
849*f4b3ec61Sdh 		if (node != NULL) {
850*f4b3ec61Sdh 			WRITE_ENTER(&ifs->ifs_ip_poolrw);
851*f4b3ec61Sdh 			ip_pool_node_deref(node, ifs);
852*f4b3ec61Sdh 			RWLOCK_EXIT(&ifs->ifs_ip_poolrw);
853*f4b3ec61Sdh 		}
854*f4b3ec61Sdh 		token->ipt_data = nextnode;
855*f4b3ec61Sdh 		err = COPYOUT(nextnode, ilp->ili_data, sizeof(*nextnode));
856*f4b3ec61Sdh 		if (err != 0)
857*f4b3ec61Sdh 			err = EFAULT;
858*f4b3ec61Sdh 		break;
859*f4b3ec61Sdh 	}
860*f4b3ec61Sdh 
861*f4b3ec61Sdh 	return err;
862*f4b3ec61Sdh }
863*f4b3ec61Sdh 
864*f4b3ec61Sdh 
865*f4b3ec61Sdh void ip_pool_iterderef(otype, unit, data, ifs)
866*f4b3ec61Sdh u_int otype;
867*f4b3ec61Sdh int unit;
868*f4b3ec61Sdh void *data;
869*f4b3ec61Sdh ipf_stack_t *ifs;
870*f4b3ec61Sdh {
871*f4b3ec61Sdh 
872*f4b3ec61Sdh 	if (data == NULL)
873*f4b3ec61Sdh 		return;
874*f4b3ec61Sdh 
875*f4b3ec61Sdh 	if (unit < 0 || unit > IPL_LOGMAX)
876*f4b3ec61Sdh 		return;
877*f4b3ec61Sdh 
878*f4b3ec61Sdh 	switch (otype)
879*f4b3ec61Sdh 	{
880*f4b3ec61Sdh 	case IPFLOOKUPITER_LIST :
881*f4b3ec61Sdh 		WRITE_ENTER(&ifs->ifs_ip_poolrw);
882*f4b3ec61Sdh 		ip_pool_deref((ip_pool_t *)data, ifs);
883*f4b3ec61Sdh 		RWLOCK_EXIT(&ifs->ifs_ip_poolrw);
884*f4b3ec61Sdh 		break;
885*f4b3ec61Sdh 
886*f4b3ec61Sdh 	case IPFLOOKUPITER_NODE :
887*f4b3ec61Sdh 		WRITE_ENTER(&ifs->ifs_ip_poolrw);
888*f4b3ec61Sdh 		ip_pool_node_deref((ip_pool_node_t *)data, ifs);
889*f4b3ec61Sdh 		RWLOCK_EXIT(&ifs->ifs_ip_poolrw);
890*f4b3ec61Sdh 		break;
891*f4b3ec61Sdh 	default :
892*f4b3ec61Sdh 		break;
893*f4b3ec61Sdh 	}
8947c478bd9Sstevel@tonic-gate }
8957c478bd9Sstevel@tonic-gate 
8967c478bd9Sstevel@tonic-gate 
897ab25eeb5Syz # if defined(_KERNEL) && ((BSD >= 198911) && !defined(__osf__) && \
898ab25eeb5Syz       !defined(__hpux) && !defined(__sgi))
8997c478bd9Sstevel@tonic-gate static int
900*f4b3ec61Sdh rn_freenode(struct radix_node *n, void *p, ipf_stack_t *ifs)
9017c478bd9Sstevel@tonic-gate {
9027c478bd9Sstevel@tonic-gate 	struct radix_node_head *rnh = p;
9037c478bd9Sstevel@tonic-gate 	struct radix_node *d;
9047c478bd9Sstevel@tonic-gate 
9057c478bd9Sstevel@tonic-gate 	d = rnh->rnh_deladdr(n->rn_key, NULL, rnh);
9067c478bd9Sstevel@tonic-gate 	if (d != NULL) {
907*f4b3ec61Sdh 		FreeS(d, ifs->ifs_max_keylen + 2 * sizeof (*d));
9087c478bd9Sstevel@tonic-gate 	}
9097c478bd9Sstevel@tonic-gate 	return 0;
9107c478bd9Sstevel@tonic-gate }
9117c478bd9Sstevel@tonic-gate 
9127c478bd9Sstevel@tonic-gate 
9137c478bd9Sstevel@tonic-gate void
9147c478bd9Sstevel@tonic-gate rn_freehead(rnh)
9157c478bd9Sstevel@tonic-gate       struct radix_node_head *rnh;
9167c478bd9Sstevel@tonic-gate {
9177c478bd9Sstevel@tonic-gate 
918ab25eeb5Syz 	(*rnh->rnh_walktree)(rnh, rn_freenode, rnh);
9197c478bd9Sstevel@tonic-gate 
9207c478bd9Sstevel@tonic-gate 	rnh->rnh_addaddr = NULL;
9217c478bd9Sstevel@tonic-gate 	rnh->rnh_deladdr = NULL;
9227c478bd9Sstevel@tonic-gate 	rnh->rnh_matchaddr = NULL;
9237c478bd9Sstevel@tonic-gate 	rnh->rnh_lookup = NULL;
9247c478bd9Sstevel@tonic-gate 	rnh->rnh_walktree = NULL;
9257c478bd9Sstevel@tonic-gate 
9267c478bd9Sstevel@tonic-gate 	Free(rnh);
9277c478bd9Sstevel@tonic-gate }
9287c478bd9Sstevel@tonic-gate # endif
9297c478bd9Sstevel@tonic-gate 
9307c478bd9Sstevel@tonic-gate #endif /* IPFILTER_LOOKUP */
931