xref: /netbsd-src/external/bsd/ipf/dist/ip_pool.c (revision 13885a665959c62f13a82b3caedf986eaa17aa31)
1*13885a66Sdarrenr /*	$NetBSD: ip_pool.c,v 1.2 2012/07/22 14:27:35 darrenr Exp $	*/
2bc4097aaSchristos 
3bc4097aaSchristos /*
4bc4097aaSchristos  * Copyright (C) 2012 by Darren Reed.
5bc4097aaSchristos  *
6bc4097aaSchristos  * See the IPFILTER.LICENCE file for details on licencing.
7bc4097aaSchristos  */
8bc4097aaSchristos #if defined(KERNEL) || defined(_KERNEL)
9bc4097aaSchristos # undef KERNEL
10bc4097aaSchristos # undef _KERNEL
11bc4097aaSchristos # define        KERNEL	1
12bc4097aaSchristos # define        _KERNEL	1
13bc4097aaSchristos #endif
14bc4097aaSchristos #if defined(__osf__)
15bc4097aaSchristos # define _PROTO_NET_H_
16bc4097aaSchristos #endif
17bc4097aaSchristos #include <sys/errno.h>
18bc4097aaSchristos #include <sys/types.h>
19bc4097aaSchristos #include <sys/param.h>
20bc4097aaSchristos #include <sys/file.h>
21bc4097aaSchristos #if !defined(_KERNEL) && !defined(__KERNEL__)
22bc4097aaSchristos # include <stdio.h>
23bc4097aaSchristos # include <stdlib.h>
24bc4097aaSchristos # include <string.h>
25bc4097aaSchristos # define _KERNEL
26bc4097aaSchristos # ifdef __OpenBSD__
27bc4097aaSchristos struct file;
28bc4097aaSchristos # endif
29bc4097aaSchristos # include <sys/uio.h>
30bc4097aaSchristos # undef _KERNEL
31bc4097aaSchristos #else
32bc4097aaSchristos # include <sys/systm.h>
33bc4097aaSchristos # if defined(NetBSD) && (__NetBSD_Version__ >= 104000000)
34bc4097aaSchristos #  include <sys/proc.h>
35bc4097aaSchristos # endif
36bc4097aaSchristos #endif
37bc4097aaSchristos #include <sys/time.h>
38bc4097aaSchristos #if defined(_KERNEL) && !defined(SOLARIS2)
39bc4097aaSchristos # include <sys/mbuf.h>
40bc4097aaSchristos #endif
41bc4097aaSchristos #if defined(__SVR4) || defined(__svr4__)
42bc4097aaSchristos # include <sys/byteorder.h>
43bc4097aaSchristos # ifdef _KERNEL
44bc4097aaSchristos #  include <sys/dditypes.h>
45bc4097aaSchristos # endif
46bc4097aaSchristos # include <sys/stream.h>
47bc4097aaSchristos # include <sys/kmem.h>
48bc4097aaSchristos #endif
49bc4097aaSchristos #if defined(__FreeBSD_version) && (__FreeBSD_version >= 300000)
50bc4097aaSchristos # include <sys/malloc.h>
51bc4097aaSchristos #endif
52bc4097aaSchristos 
53bc4097aaSchristos #include <sys/socket.h>
54bc4097aaSchristos #include <net/if.h>
55bc4097aaSchristos #include <netinet/in.h>
56bc4097aaSchristos #if !defined(_KERNEL)
57bc4097aaSchristos # include "ipf.h"
58bc4097aaSchristos #endif
59bc4097aaSchristos 
60bc4097aaSchristos #include "netinet/ip_compat.h"
61bc4097aaSchristos #include "netinet/ip_fil.h"
62bc4097aaSchristos #include "netinet/ip_pool.h"
63bc4097aaSchristos #include "netinet/radix_ipf.h"
64bc4097aaSchristos 
65bc4097aaSchristos /* END OF INCLUDES */
66bc4097aaSchristos 
67bc4097aaSchristos #if !defined(lint)
68bc4097aaSchristos static const char sccsid[] = "@(#)ip_fil.c	2.41 6/5/96 (C) 1993-2000 Darren Reed";
69*13885a66Sdarrenr static const char rcsid[] = "@(#)Id: ip_pool.c,v 1.1.1.2 2012/07/22 13:44:22 darrenr Exp $";
70bc4097aaSchristos #endif
71bc4097aaSchristos 
72bc4097aaSchristos typedef struct ipf_pool_softc_s {
73bc4097aaSchristos 	void		*ipf_radix;
74bc4097aaSchristos 	ip_pool_t	*ipf_pool_list[LOOKUP_POOL_SZ];
75bc4097aaSchristos 	ipf_pool_stat_t	ipf_pool_stats;
76bc4097aaSchristos 	ip_pool_node_t	*ipf_node_explist;
77bc4097aaSchristos } ipf_pool_softc_t;
78bc4097aaSchristos 
79bc4097aaSchristos 
80c9d5dc6cSdarrenr static void ipf_pool_clearnodes __P((ipf_main_softc_t *, ipf_pool_softc_t *,
81c9d5dc6cSdarrenr 				     ip_pool_t *));
82bc4097aaSchristos static int ipf_pool_create __P((ipf_main_softc_t *, ipf_pool_softc_t *, iplookupop_t *));
83bc4097aaSchristos static int ipf_pool_deref __P((ipf_main_softc_t *, void *, void *));
84bc4097aaSchristos static int ipf_pool_destroy __P((ipf_main_softc_t *, ipf_pool_softc_t *, int, char *));
85bc4097aaSchristos static void *ipf_pool_exists __P((ipf_pool_softc_t *, int, char *));
86bc4097aaSchristos static void *ipf_pool_find __P((void *, int, char *));
87bc4097aaSchristos static ip_pool_node_t *ipf_pool_findeq __P((ipf_pool_softc_t *, ip_pool_t *,
88bc4097aaSchristos 					    addrfamily_t *, addrfamily_t *));
89c9d5dc6cSdarrenr static void ipf_pool_free __P((ipf_main_softc_t *, ipf_pool_softc_t *,
90c9d5dc6cSdarrenr 			       ip_pool_t *));
91bc4097aaSchristos static int ipf_pool_insert_node __P((ipf_main_softc_t *, ipf_pool_softc_t *,
92bc4097aaSchristos 				     ip_pool_t *, struct ip_pool_node *));
93bc4097aaSchristos static int ipf_pool_iter_deref __P((ipf_main_softc_t *, void *, int, int, void *));
94bc4097aaSchristos static int ipf_pool_iter_next __P((ipf_main_softc_t *,  void *, ipftoken_t *,
95bc4097aaSchristos 				   ipflookupiter_t *));
96bc4097aaSchristos static size_t ipf_pool_flush __P((ipf_main_softc_t *, void *, iplookupflush_t *));
97bc4097aaSchristos static int ipf_pool_node_add __P((ipf_main_softc_t *, void *, iplookupop_t *,
98bc4097aaSchristos 				  int));
99bc4097aaSchristos static int ipf_pool_node_del __P((ipf_main_softc_t *, void *, iplookupop_t *,
100bc4097aaSchristos 				  int));
101bc4097aaSchristos static void ipf_pool_node_deref __P((ipf_pool_softc_t *, ip_pool_node_t *));
102c9d5dc6cSdarrenr static int ipf_pool_remove_node __P((ipf_main_softc_t *, ipf_pool_softc_t *,
103c9d5dc6cSdarrenr 				     ip_pool_t *, ip_pool_node_t *));
104bc4097aaSchristos static int ipf_pool_search __P((ipf_main_softc_t *, void *, int,
105bc4097aaSchristos 				void *, u_int));
106bc4097aaSchristos static void *ipf_pool_soft_create __P((ipf_main_softc_t *));
107bc4097aaSchristos static void ipf_pool_soft_destroy __P((ipf_main_softc_t *, void *));
108bc4097aaSchristos static void ipf_pool_soft_fini __P((ipf_main_softc_t *, void *));
109bc4097aaSchristos static int ipf_pool_soft_init __P((ipf_main_softc_t *, void *));
110bc4097aaSchristos static int ipf_pool_stats_get __P((ipf_main_softc_t *, void *, iplookupop_t *));
111bc4097aaSchristos static int ipf_pool_table_add __P((ipf_main_softc_t *, void *, iplookupop_t *));
112bc4097aaSchristos static int ipf_pool_table_del __P((ipf_main_softc_t *, void *, iplookupop_t *));
113bc4097aaSchristos static void *ipf_pool_select_add_ref __P((void *, int, char *));
114bc4097aaSchristos static void ipf_pool_expire __P((ipf_main_softc_t *, void *));
115bc4097aaSchristos 
116bc4097aaSchristos ipf_lookup_t ipf_pool_backend = {
117bc4097aaSchristos 	IPLT_POOL,
118bc4097aaSchristos 	ipf_pool_soft_create,
119bc4097aaSchristos 	ipf_pool_soft_destroy,
120bc4097aaSchristos 	ipf_pool_soft_init,
121bc4097aaSchristos 	ipf_pool_soft_fini,
122bc4097aaSchristos 	ipf_pool_search,
123bc4097aaSchristos 	ipf_pool_flush,
124bc4097aaSchristos 	ipf_pool_iter_deref,
125bc4097aaSchristos 	ipf_pool_iter_next,
126bc4097aaSchristos 	ipf_pool_node_add,
127bc4097aaSchristos 	ipf_pool_node_del,
128bc4097aaSchristos 	ipf_pool_stats_get,
129bc4097aaSchristos 	ipf_pool_table_add,
130bc4097aaSchristos 	ipf_pool_table_del,
131bc4097aaSchristos 	ipf_pool_deref,
132bc4097aaSchristos 	ipf_pool_find,
133bc4097aaSchristos 	ipf_pool_select_add_ref,
134bc4097aaSchristos 	NULL,
135bc4097aaSchristos 	ipf_pool_expire,
136bc4097aaSchristos 	NULL
137bc4097aaSchristos };
138bc4097aaSchristos 
139bc4097aaSchristos 
140bc4097aaSchristos #ifdef TEST_POOL
141bc4097aaSchristos void treeprint __P((ip_pool_t *));
142bc4097aaSchristos 
143bc4097aaSchristos int
main(argc,argv)144bc4097aaSchristos main(argc, argv)
145bc4097aaSchristos 	int argc;
146bc4097aaSchristos 	char *argv[];
147bc4097aaSchristos {
148bc4097aaSchristos 	ip_pool_node_t node;
149bc4097aaSchristos 	addrfamily_t a, b;
150bc4097aaSchristos 	iplookupop_t op;
151bc4097aaSchristos 	ip_pool_t *ipo;
152bc4097aaSchristos 	i6addr_t ip;
153bc4097aaSchristos 
154bc4097aaSchristos 	RWLOCK_INIT(softc->ipf_poolrw, "poolrw");
155bc4097aaSchristos 	ipf_pool_init();
156bc4097aaSchristos 
157bc4097aaSchristos 	bzero((char *)&ip, sizeof(ip));
158bc4097aaSchristos 	bzero((char *)&op, sizeof(op));
159bc4097aaSchristos 	bzero((char *)&node, sizeof(node));
160bc4097aaSchristos 	strcpy(op.iplo_name, "0");
161bc4097aaSchristos 
162bc4097aaSchristos 	if (ipf_pool_create(&op) == 0)
163bc4097aaSchristos 		ipo = ipf_pool_exists(0, "0");
164bc4097aaSchristos 
165bc4097aaSchristos 	node.ipn_addr.adf_family = AF_INET;
166bc4097aaSchristos 
167bc4097aaSchristos 	node.ipn_addr.adf_addr.in4.s_addr = 0x0a010203;
168bc4097aaSchristos 	node.ipn_mask.adf_addr.in4.s_addr = 0xffffffff;
169bc4097aaSchristos 	node.ipn_info = 1;
170bc4097aaSchristos 	ipf_pool_insert_node(ipo, &node);
171bc4097aaSchristos 
172bc4097aaSchristos 	node.ipn_addr.adf_addr.in4.s_addr = 0x0a000000;
173bc4097aaSchristos 	node.ipn_mask.adf_addr.in4.s_addr = 0xff000000;
174bc4097aaSchristos 	node.ipn_info = 0;
175bc4097aaSchristos 	ipf_pool_insert_node(ipo, &node);
176bc4097aaSchristos 
177bc4097aaSchristos 	node.ipn_addr.adf_addr.in4.s_addr = 0x0a010100;
178bc4097aaSchristos 	node.ipn_mask.adf_addr.in4.s_addr = 0xffffff00;
179bc4097aaSchristos 	node.ipn_info = 1;
180bc4097aaSchristos 	ipf_pool_insert_node(ipo, &node);
181bc4097aaSchristos 
182bc4097aaSchristos 	node.ipn_addr.adf_addr.in4.s_addr = 0x0a010200;
183bc4097aaSchristos 	node.ipn_mask.adf_addr.in4.s_addr = 0xffffff00;
184bc4097aaSchristos 	node.ipn_info = 0;
185bc4097aaSchristos 	ipf_pool_insert_node(ipo, &node);
186bc4097aaSchristos 
187bc4097aaSchristos 	node.ipn_addr.adf_addr.in4.s_addr = 0x0a010000;
188bc4097aaSchristos 	node.ipn_mask.adf_addr.in4.s_addr = 0xffff0000;
189bc4097aaSchristos 	node.ipn_info = 1;
190bc4097aaSchristos 	ipf_pool_insert_node(ipo, &node);
191bc4097aaSchristos 
192bc4097aaSchristos 	node.ipn_addr.adf_addr.in4.s_addr = 0x0a01020f;
193bc4097aaSchristos 	node.ipn_mask.adf_addr.in4.s_addr = 0xffffffff;
194bc4097aaSchristos 	node.ipn_info = 1;
195bc4097aaSchristos 	ipf_pool_insert_node(ipo, &node);
196bc4097aaSchristos #ifdef	DEBUG_POOL
197bc4097aaSchristos 	treeprint(ipo);
198bc4097aaSchristos #endif
199bc4097aaSchristos 	ip.in4.s_addr = 0x0a00aabb;
200bc4097aaSchristos 	printf("search(%#x) = %d (0)\n", ip.in4.s_addr,
201bc4097aaSchristos 		ipf_pool_search(ipo, 4, &ip, 1));
202bc4097aaSchristos 
203bc4097aaSchristos 	ip.in4.s_addr = 0x0a000001;
204bc4097aaSchristos 	printf("search(%#x) = %d (0)\n", ip.in4.s_addr,
205bc4097aaSchristos 		ipf_pool_search(ipo, 4, &ip, 1));
206bc4097aaSchristos 
207bc4097aaSchristos 	ip.in4.s_addr = 0x0a000101;
208bc4097aaSchristos 	printf("search(%#x) = %d (0)\n", ip.in4.s_addr,
209bc4097aaSchristos 		ipf_pool_search(ipo, 4, &ip, 1));
210bc4097aaSchristos 
211bc4097aaSchristos 	ip.in4.s_addr = 0x0a010001;
212bc4097aaSchristos 	printf("search(%#x) = %d (1)\n", ip.in4.s_addr,
213bc4097aaSchristos 		ipf_pool_search(ipo, 4, &ip, 1));
214bc4097aaSchristos 
215bc4097aaSchristos 	ip.in4.s_addr = 0x0a010101;
216bc4097aaSchristos 	printf("search(%#x) = %d (1)\n", ip.in4.s_addr,
217bc4097aaSchristos 		ipf_pool_search(ipo, 4, &ip, 1));
218bc4097aaSchristos 
219bc4097aaSchristos 	ip.in4.s_addr = 0x0a010201;
220bc4097aaSchristos 	printf("search(%#x) = %d (0)\n", ip.in4.s_addr,
221bc4097aaSchristos 		ipf_pool_search(ipo, 4, &ip, 1));
222bc4097aaSchristos 
223bc4097aaSchristos 	ip.in4.s_addr = 0x0a010203;
224bc4097aaSchristos 	printf("search(%#x) = %d (1)\n", ip.in4.s_addr,
225bc4097aaSchristos 		ipf_pool_search(ipo, 4, &ip, 1));
226bc4097aaSchristos 
227bc4097aaSchristos 	ip.in4.s_addr = 0x0a01020f;
228bc4097aaSchristos 	printf("search(%#x) = %d (1)\n", ip.in4.s_addr,
229bc4097aaSchristos 		ipf_pool_search(ipo, 4, &ip, 1));
230bc4097aaSchristos 
231bc4097aaSchristos 	ip.in4.s_addr = 0x0b00aabb;
232bc4097aaSchristos 	printf("search(%#x) = %d (-1)\n", ip.in4.s_addr,
233bc4097aaSchristos 		ipf_pool_search(ipo, 4, &ip, 1));
234bc4097aaSchristos 
235bc4097aaSchristos #ifdef	DEBUG_POOL
236bc4097aaSchristos 	treeprint(ipo);
237bc4097aaSchristos #endif
238bc4097aaSchristos 
239bc4097aaSchristos 	ipf_pool_fini();
240bc4097aaSchristos 
241bc4097aaSchristos 	return 0;
242bc4097aaSchristos }
243bc4097aaSchristos 
244bc4097aaSchristos 
245bc4097aaSchristos void
treeprint(ipo)246bc4097aaSchristos treeprint(ipo)
247bc4097aaSchristos 	ip_pool_t *ipo;
248bc4097aaSchristos {
249bc4097aaSchristos 	ip_pool_node_t *c;
250bc4097aaSchristos 
251bc4097aaSchristos 	for (c = ipo->ipo_list; c != NULL; c = c->ipn_next)
252bc4097aaSchristos 		printf("Node %p(%s) (%#x/%#x) = %d hits %lu\n",
253bc4097aaSchristos 			c, c->ipn_name, c->ipn_addr.adf_addr.in4.s_addr,
254bc4097aaSchristos 			c->ipn_mask.adf_addr.in4.s_addr,
255bc4097aaSchristos 			c->ipn_info, c->ipn_hits);
256bc4097aaSchristos }
257bc4097aaSchristos #endif /* TEST_POOL */
258bc4097aaSchristos 
259bc4097aaSchristos 
260bc4097aaSchristos /* ------------------------------------------------------------------------ */
261bc4097aaSchristos /* Function:    ipf_pool_soft_create                                        */
262bc4097aaSchristos /* Returns:     void *   - NULL = failure, else pointer to local context    */
263bc4097aaSchristos /* Parameters:  softc(I) - pointer to soft context main structure           */
264bc4097aaSchristos /*                                                                          */
265bc4097aaSchristos /* Initialise the routing table data structures where required.             */
266bc4097aaSchristos /* ------------------------------------------------------------------------ */
267bc4097aaSchristos static void *
ipf_pool_soft_create(softc)268bc4097aaSchristos ipf_pool_soft_create(softc)
269bc4097aaSchristos 	ipf_main_softc_t *softc;
270bc4097aaSchristos {
271bc4097aaSchristos 	ipf_pool_softc_t *softp;
272bc4097aaSchristos 
273bc4097aaSchristos 	KMALLOC(softp, ipf_pool_softc_t *);
274c9d5dc6cSdarrenr 	if (softp == NULL) {
275c9d5dc6cSdarrenr 		IPFERROR(70032);
276bc4097aaSchristos 		return NULL;
277c9d5dc6cSdarrenr 	}
278bc4097aaSchristos 
279bc4097aaSchristos 	bzero((char *)softp, sizeof(*softp));
280bc4097aaSchristos 
281bc4097aaSchristos 	softp->ipf_radix = ipf_rx_create();
282bc4097aaSchristos 	if (softp->ipf_radix == NULL) {
283c9d5dc6cSdarrenr 		IPFERROR(70033);
284bc4097aaSchristos 		KFREE(softp);
285bc4097aaSchristos 		return NULL;
286bc4097aaSchristos 	}
287bc4097aaSchristos 
288bc4097aaSchristos 	return softp;
289bc4097aaSchristos }
290bc4097aaSchristos 
291bc4097aaSchristos 
292bc4097aaSchristos /* ------------------------------------------------------------------------ */
293bc4097aaSchristos /* Function:    ipf_pool_soft_init                                          */
294bc4097aaSchristos /* Returns:     int     - 0 = success, else error                           */
295bc4097aaSchristos /* Parameters:  softc(I) - pointer to soft context main structure           */
296bc4097aaSchristos /*              arg(I)   - pointer to local context to use                  */
297bc4097aaSchristos /*                                                                          */
298bc4097aaSchristos /* Initialise the routing table data structures where required.             */
299bc4097aaSchristos /* ------------------------------------------------------------------------ */
300bc4097aaSchristos static int
ipf_pool_soft_init(softc,arg)301bc4097aaSchristos ipf_pool_soft_init(softc, arg)
302bc4097aaSchristos 	ipf_main_softc_t *softc;
303bc4097aaSchristos 	void *arg;
304bc4097aaSchristos {
305bc4097aaSchristos 	ipf_pool_softc_t *softp = arg;
306bc4097aaSchristos 
307bc4097aaSchristos 	ipf_rx_init(softp->ipf_radix);
308bc4097aaSchristos 
309bc4097aaSchristos 	return 0;
310bc4097aaSchristos }
311bc4097aaSchristos 
312bc4097aaSchristos 
313bc4097aaSchristos /* ------------------------------------------------------------------------ */
314bc4097aaSchristos /* Function:    ipf_pool_soft_fini                                          */
315bc4097aaSchristos /* Returns:     Nil                                                         */
316bc4097aaSchristos /* Parameters:  softc(I) - pointer to soft context main structure           */
317bc4097aaSchristos /*              arg(I)   - pointer to local context to use                  */
318bc4097aaSchristos /* Locks:       WRITE(ipf_global)                                           */
319bc4097aaSchristos /*                                                                          */
320bc4097aaSchristos /* Clean up all the pool data structures allocated and call the cleanup     */
321bc4097aaSchristos /* function for the radix tree that supports the pools. ipf_pool_destroy is */
322bc4097aaSchristos /* used to delete the pools one by one to ensure they're properly freed up. */
323bc4097aaSchristos /* ------------------------------------------------------------------------ */
324bc4097aaSchristos static void
ipf_pool_soft_fini(softc,arg)325bc4097aaSchristos ipf_pool_soft_fini(softc, arg)
326bc4097aaSchristos 	ipf_main_softc_t *softc;
327bc4097aaSchristos 	void *arg;
328bc4097aaSchristos {
329bc4097aaSchristos 	ipf_pool_softc_t *softp = arg;
330bc4097aaSchristos 	ip_pool_t *p, *q;
331bc4097aaSchristos 	int i;
332bc4097aaSchristos 
333bc4097aaSchristos 	softc = arg;
334bc4097aaSchristos 
335bc4097aaSchristos 	for (i = -1; i <= IPL_LOGMAX; i++) {
336bc4097aaSchristos 		for (q = softp->ipf_pool_list[i + 1]; (p = q) != NULL; ) {
337bc4097aaSchristos 			q = p->ipo_next;
338bc4097aaSchristos 			(void) ipf_pool_destroy(softc, arg, i, p->ipo_name);
339bc4097aaSchristos 		}
340bc4097aaSchristos 	}
341bc4097aaSchristos }
342bc4097aaSchristos 
343bc4097aaSchristos 
344bc4097aaSchristos /* ------------------------------------------------------------------------ */
345bc4097aaSchristos /* Function:    ipf_pool_soft_destroy                                       */
346bc4097aaSchristos /* Returns:     Nil                                                         */
347bc4097aaSchristos /* Parameters:  softc(I) - pointer to soft context main structure           */
348bc4097aaSchristos /*              arg(I)   - pointer to local context to use                  */
349bc4097aaSchristos /*                                                                          */
350bc4097aaSchristos /* Clean up the pool by free'ing the radix tree associated with it and free */
351bc4097aaSchristos /* up the pool context too.                                                 */
352bc4097aaSchristos /* ------------------------------------------------------------------------ */
353bc4097aaSchristos static void
ipf_pool_soft_destroy(softc,arg)354bc4097aaSchristos ipf_pool_soft_destroy(softc, arg)
355bc4097aaSchristos 	ipf_main_softc_t *softc;
356bc4097aaSchristos 	void *arg;
357bc4097aaSchristos {
358bc4097aaSchristos 	ipf_pool_softc_t *softp = arg;
359bc4097aaSchristos 
360bc4097aaSchristos 	ipf_rx_destroy(softp->ipf_radix);
361bc4097aaSchristos 
362bc4097aaSchristos 	KFREE(softp);
363bc4097aaSchristos }
364bc4097aaSchristos 
365bc4097aaSchristos 
366bc4097aaSchristos /* ------------------------------------------------------------------------ */
367bc4097aaSchristos /* Function:   ipf_pool_node_add                                            */
368bc4097aaSchristos /* Returns:    int - 0 = success, else error                                */
369bc4097aaSchristos /* Parameters: softc(I) - pointer to soft context main structure            */
370bc4097aaSchristos /*             arg(I)   - pointer to local context to use                   */
371bc4097aaSchristos /*             op(I) - pointer to lookup operatin data                      */
372bc4097aaSchristos /*                                                                          */
373c9d5dc6cSdarrenr /* When adding a new node, a check is made to ensure that the address/mask  */
374c9d5dc6cSdarrenr /* pair supplied has been appropriately prepared by applying the mask to    */
375c9d5dc6cSdarrenr /* the address prior to calling for the pair to be added.                   */
376bc4097aaSchristos /* ------------------------------------------------------------------------ */
377bc4097aaSchristos static int
ipf_pool_node_add(softc,arg,op,uid)378bc4097aaSchristos ipf_pool_node_add(softc, arg, op, uid)
379bc4097aaSchristos 	ipf_main_softc_t *softc;
380bc4097aaSchristos 	void *arg;
381bc4097aaSchristos 	iplookupop_t *op;
382bc4097aaSchristos 	int uid;
383bc4097aaSchristos {
384bc4097aaSchristos 	ip_pool_node_t node, *m;
385bc4097aaSchristos 	ip_pool_t *p;
386bc4097aaSchristos 	int err;
387bc4097aaSchristos 
388bc4097aaSchristos 	if (op->iplo_size != sizeof(node)) {
389bc4097aaSchristos 		IPFERROR(70014);
390bc4097aaSchristos 		return EINVAL;
391bc4097aaSchristos 	}
392bc4097aaSchristos 
393bc4097aaSchristos 	err = COPYIN(op->iplo_struct, &node, sizeof(node));
394bc4097aaSchristos 	if (err != 0) {
395bc4097aaSchristos 		IPFERROR(70015);
396bc4097aaSchristos 		return EFAULT;
397bc4097aaSchristos 	}
398bc4097aaSchristos 
399bc4097aaSchristos 	p = ipf_pool_find(arg, op->iplo_unit, op->iplo_name);
400bc4097aaSchristos 	if (p == NULL) {
401bc4097aaSchristos 		IPFERROR(70017);
402bc4097aaSchristos 		return ESRCH;
403bc4097aaSchristos 	}
404bc4097aaSchristos 
405c9d5dc6cSdarrenr 	if (node.ipn_addr.adf_family == AF_INET) {
406c9d5dc6cSdarrenr 		if (node.ipn_addr.adf_len != offsetof(addrfamily_t, adf_addr) +
407c9d5dc6cSdarrenr 					     sizeof(struct in_addr)) {
408c9d5dc6cSdarrenr 			IPFERROR(70028);
409c9d5dc6cSdarrenr 			return EINVAL;
410c9d5dc6cSdarrenr 		}
411c9d5dc6cSdarrenr 	}
412c9d5dc6cSdarrenr #ifdef USE_INET6
413c9d5dc6cSdarrenr 	else if (node.ipn_addr.adf_family == AF_INET6) {
414c9d5dc6cSdarrenr 		if (node.ipn_addr.adf_len != offsetof(addrfamily_t, adf_addr) +
415c9d5dc6cSdarrenr 					     sizeof(struct in6_addr)) {
416c9d5dc6cSdarrenr 			IPFERROR(70034);
417c9d5dc6cSdarrenr 			return EINVAL;
418c9d5dc6cSdarrenr 		}
419c9d5dc6cSdarrenr 	}
420c9d5dc6cSdarrenr #endif
421c9d5dc6cSdarrenr 	if (node.ipn_mask.adf_len != node.ipn_addr.adf_len) {
422c9d5dc6cSdarrenr 		IPFERROR(70029);
423c9d5dc6cSdarrenr 		return EINVAL;
424c9d5dc6cSdarrenr 	}
425c9d5dc6cSdarrenr 
426c9d5dc6cSdarrenr 	/*
427c9d5dc6cSdarrenr 	 * Check that the address/mask pair works.
428c9d5dc6cSdarrenr 	 */
429c9d5dc6cSdarrenr 	if (node.ipn_addr.adf_family == AF_INET) {
430c9d5dc6cSdarrenr 		if ((node.ipn_addr.adf_addr.in4.s_addr &
431c9d5dc6cSdarrenr 		     node.ipn_mask.adf_addr.in4.s_addr) !=
432c9d5dc6cSdarrenr 		    node.ipn_addr.adf_addr.in4.s_addr) {
433c9d5dc6cSdarrenr 			IPFERROR(70035);
434c9d5dc6cSdarrenr 			return EINVAL;
435c9d5dc6cSdarrenr 		}
436c9d5dc6cSdarrenr 	}
437c9d5dc6cSdarrenr #ifdef USE_INET6
438c9d5dc6cSdarrenr 	else if (node.ipn_addr.adf_family == AF_INET6) {
439c9d5dc6cSdarrenr 		if (IP6_MASKNEQ(&node.ipn_addr.adf_addr.in6,
440c9d5dc6cSdarrenr 				&node.ipn_mask.adf_addr.in6,
441c9d5dc6cSdarrenr 				&node.ipn_addr.adf_addr.in6)) {
442c9d5dc6cSdarrenr 			IPFERROR(70036);
443c9d5dc6cSdarrenr 			return EINVAL;
444c9d5dc6cSdarrenr 		}
445c9d5dc6cSdarrenr 	}
446c9d5dc6cSdarrenr #endif
447c9d5dc6cSdarrenr 
448bc4097aaSchristos 	/*
449bc4097aaSchristos 	 * add an entry to a pool - return an error if it already
450bc4097aaSchristos 	 * exists remove an entry from a pool - if it exists
451bc4097aaSchristos 	 * - in both cases, the pool *must* exist!
452bc4097aaSchristos 	 */
453bc4097aaSchristos 	m = ipf_pool_findeq(arg, p, &node.ipn_addr, &node.ipn_mask);
454bc4097aaSchristos 	if (m != NULL) {
455bc4097aaSchristos 		IPFERROR(70018);
456bc4097aaSchristos 		return EEXIST;
457bc4097aaSchristos 	}
458bc4097aaSchristos 	err = ipf_pool_insert_node(softc, arg, p, &node);
459bc4097aaSchristos 
460bc4097aaSchristos 	return err;
461bc4097aaSchristos }
462bc4097aaSchristos 
463bc4097aaSchristos 
464bc4097aaSchristos /* ------------------------------------------------------------------------ */
465bc4097aaSchristos /* Function:   ipf_pool_node_del                                            */
466bc4097aaSchristos /* Returns:    int - 0 = success, else error                                */
467bc4097aaSchristos /* Parameters: softc(I) - pointer to soft context main structure            */
468bc4097aaSchristos /*             arg(I)   - pointer to local context to use                   */
469bc4097aaSchristos /*             op(I)    - pointer to lookup operatin data                   */
470bc4097aaSchristos /*                                                                          */
471bc4097aaSchristos /* ------------------------------------------------------------------------ */
472bc4097aaSchristos static int
ipf_pool_node_del(softc,arg,op,uid)473bc4097aaSchristos ipf_pool_node_del(softc, arg, op, uid)
474bc4097aaSchristos 	ipf_main_softc_t *softc;
475bc4097aaSchristos 	void *arg;
476bc4097aaSchristos 	iplookupop_t *op;
477bc4097aaSchristos 	int uid;
478bc4097aaSchristos {
479bc4097aaSchristos 	ip_pool_node_t node, *m;
480bc4097aaSchristos 	ip_pool_t *p;
481bc4097aaSchristos 	int err;
482bc4097aaSchristos 
483bc4097aaSchristos 
484bc4097aaSchristos 	if (op->iplo_size != sizeof(node)) {
485bc4097aaSchristos 		IPFERROR(70019);
486bc4097aaSchristos 		return EINVAL;
487bc4097aaSchristos 	}
488bc4097aaSchristos 	node.ipn_uid = uid;
489bc4097aaSchristos 
490bc4097aaSchristos 	err = COPYIN(op->iplo_struct, &node, sizeof(node));
491bc4097aaSchristos 	if (err != 0) {
492bc4097aaSchristos 		IPFERROR(70020);
493bc4097aaSchristos 		return EFAULT;
494bc4097aaSchristos 	}
495bc4097aaSchristos 
496c9d5dc6cSdarrenr 	if (node.ipn_addr.adf_family == AF_INET) {
497c9d5dc6cSdarrenr 		if (node.ipn_addr.adf_len != offsetof(addrfamily_t, adf_addr) +
498c9d5dc6cSdarrenr 					     sizeof(struct in_addr)) {
499c9d5dc6cSdarrenr 			IPFERROR(70030);
500c9d5dc6cSdarrenr 			return EINVAL;
501c9d5dc6cSdarrenr 		}
502c9d5dc6cSdarrenr 	}
503c9d5dc6cSdarrenr #ifdef USE_INET6
504c9d5dc6cSdarrenr 	else if (node.ipn_addr.adf_family == AF_INET6) {
505c9d5dc6cSdarrenr 		if (node.ipn_addr.adf_len != offsetof(addrfamily_t, adf_addr) +
506c9d5dc6cSdarrenr 					     sizeof(struct in6_addr)) {
507c9d5dc6cSdarrenr 			IPFERROR(70037);
508c9d5dc6cSdarrenr 			return EINVAL;
509c9d5dc6cSdarrenr 		}
510c9d5dc6cSdarrenr 	}
511c9d5dc6cSdarrenr #endif
512c9d5dc6cSdarrenr 	if (node.ipn_mask.adf_len != node.ipn_addr.adf_len) {
513c9d5dc6cSdarrenr 		IPFERROR(70031);
514c9d5dc6cSdarrenr 		return EINVAL;
515c9d5dc6cSdarrenr 	}
516c9d5dc6cSdarrenr 
517bc4097aaSchristos 	p = ipf_pool_find(arg, op->iplo_unit, op->iplo_name);
518bc4097aaSchristos 	if (p == NULL) {
519bc4097aaSchristos 		IPFERROR(70021);
520bc4097aaSchristos 		return ESRCH;
521bc4097aaSchristos 	}
522bc4097aaSchristos 
523bc4097aaSchristos 	m = ipf_pool_findeq(arg, p, &node.ipn_addr, &node.ipn_mask);
524bc4097aaSchristos 	if (m == NULL) {
525bc4097aaSchristos 		IPFERROR(70022);
526bc4097aaSchristos 		return ENOENT;
527bc4097aaSchristos 	}
528bc4097aaSchristos 
529bc4097aaSchristos 	if ((uid != 0) && (uid != m->ipn_uid)) {
530bc4097aaSchristos 		IPFERROR(70024);
531bc4097aaSchristos 		return EACCES;
532bc4097aaSchristos 	}
533bc4097aaSchristos 
534c9d5dc6cSdarrenr 	err = ipf_pool_remove_node(softc, arg, p, m);
535bc4097aaSchristos 
536bc4097aaSchristos 	return err;
537bc4097aaSchristos }
538bc4097aaSchristos 
539bc4097aaSchristos 
540bc4097aaSchristos /* ------------------------------------------------------------------------ */
541bc4097aaSchristos /* Function:   ipf_pool_table_add                                           */
542bc4097aaSchristos /* Returns:    int - 0 = success, else error                                */
543bc4097aaSchristos /* Parameters: softc(I) - pointer to soft context main structure            */
544bc4097aaSchristos /*             arg(I)   - pointer to local context to use                   */
545bc4097aaSchristos /*             op(I)    - pointer to lookup operatin data                   */
546bc4097aaSchristos /*                                                                          */
547bc4097aaSchristos /* ------------------------------------------------------------------------ */
548bc4097aaSchristos static int
ipf_pool_table_add(softc,arg,op)549bc4097aaSchristos ipf_pool_table_add(softc, arg, op)
550bc4097aaSchristos 	ipf_main_softc_t *softc;
551bc4097aaSchristos 	void *arg;
552bc4097aaSchristos 	iplookupop_t *op;
553bc4097aaSchristos {
554bc4097aaSchristos 	int err;
555bc4097aaSchristos 
556bc4097aaSchristos 	if (((op->iplo_arg & LOOKUP_ANON) == 0) &&
557bc4097aaSchristos 	    (ipf_pool_find(arg, op->iplo_unit, op->iplo_name) != NULL)) {
558bc4097aaSchristos 		IPFERROR(70023);
559bc4097aaSchristos 		err = EEXIST;
560bc4097aaSchristos 	} else {
561bc4097aaSchristos 		err = ipf_pool_create(softc, arg, op);
562bc4097aaSchristos 	}
563bc4097aaSchristos 
564bc4097aaSchristos 	return err;
565bc4097aaSchristos }
566bc4097aaSchristos 
567bc4097aaSchristos 
568bc4097aaSchristos /* ------------------------------------------------------------------------ */
569bc4097aaSchristos /* Function:   ipf_pool_table_del                                           */
570bc4097aaSchristos /* Returns:    int - 0 = success, else error                                */
571bc4097aaSchristos /* Parameters: softc(I) - pointer to soft context main structure            */
572bc4097aaSchristos /*             arg(I)   - pointer to local context to use                   */
573bc4097aaSchristos /*             op(I)    - pointer to lookup operatin data                   */
574bc4097aaSchristos /*                                                                          */
575bc4097aaSchristos /* ------------------------------------------------------------------------ */
576bc4097aaSchristos static int
ipf_pool_table_del(softc,arg,op)577bc4097aaSchristos ipf_pool_table_del(softc, arg, op)
578bc4097aaSchristos 	ipf_main_softc_t *softc;
579bc4097aaSchristos 	void *arg;
580bc4097aaSchristos 	iplookupop_t *op;
581bc4097aaSchristos {
582bc4097aaSchristos 	return ipf_pool_destroy(softc, arg, op->iplo_unit, op->iplo_name);
583bc4097aaSchristos }
584bc4097aaSchristos 
585bc4097aaSchristos 
586bc4097aaSchristos /* ------------------------------------------------------------------------ */
587bc4097aaSchristos /* Function:    ipf_pool_statistics                                         */
588bc4097aaSchristos /* Returns:     int      - 0 = success, else error                          */
589bc4097aaSchristos /* Parameters:  softc(I) - pointer to soft context main structure           */
590bc4097aaSchristos /*              arg(I)   - pointer to local context to use                  */
591bc4097aaSchristos /*              op(I)    - pointer to lookup operatin data                  */
592bc4097aaSchristos /*                                                                          */
593bc4097aaSchristos /* Copy the current statistics out into user space, collecting pool list    */
594bc4097aaSchristos /* pointers as appropriate for later use.                                   */
595bc4097aaSchristos /* ------------------------------------------------------------------------ */
596bc4097aaSchristos static int
ipf_pool_stats_get(softc,arg,op)597bc4097aaSchristos ipf_pool_stats_get(softc, arg, op)
598bc4097aaSchristos 	ipf_main_softc_t *softc;
599bc4097aaSchristos 	void *arg;
600bc4097aaSchristos 	iplookupop_t *op;
601bc4097aaSchristos {
602bc4097aaSchristos 	ipf_pool_softc_t *softp = arg;
603bc4097aaSchristos 	ipf_pool_stat_t stats;
604bc4097aaSchristos 	int unit, i, err = 0;
605bc4097aaSchristos 
606bc4097aaSchristos 	if (op->iplo_size != sizeof(ipf_pool_stat_t)) {
607bc4097aaSchristos 		IPFERROR(70001);
608bc4097aaSchristos 		return EINVAL;
609bc4097aaSchristos 	}
610bc4097aaSchristos 
611bc4097aaSchristos 	bcopy((char *)&softp->ipf_pool_stats, (char *)&stats, sizeof(stats));
612bc4097aaSchristos 	unit = op->iplo_unit;
613bc4097aaSchristos 	if (unit == IPL_LOGALL) {
614bc4097aaSchristos 		for (i = 0; i <= LOOKUP_POOL_MAX; i++)
615bc4097aaSchristos 			stats.ipls_list[i] = softp->ipf_pool_list[i];
616bc4097aaSchristos 	} else if (unit >= 0 && unit <= IPL_LOGMAX) {
617bc4097aaSchristos 		unit++;						/* -1 => 0 */
618bc4097aaSchristos 		if (op->iplo_name[0] != '\0')
619bc4097aaSchristos 			stats.ipls_list[unit] = ipf_pool_exists(softp, unit - 1,
620bc4097aaSchristos 								op->iplo_name);
621bc4097aaSchristos 		else
622bc4097aaSchristos 			stats.ipls_list[unit] = softp->ipf_pool_list[unit];
623bc4097aaSchristos 	} else {
624bc4097aaSchristos 		IPFERROR(70025);
625bc4097aaSchristos 		err = EINVAL;
626bc4097aaSchristos 	}
627bc4097aaSchristos 	if (err == 0) {
628bc4097aaSchristos 		err = COPYOUT(&stats, op->iplo_struct, sizeof(stats));
629bc4097aaSchristos 		if (err != 0) {
630bc4097aaSchristos 			IPFERROR(70026);
631bc4097aaSchristos 			return EFAULT;
632bc4097aaSchristos 		}
633bc4097aaSchristos 	}
634bc4097aaSchristos 	return 0;
635bc4097aaSchristos }
636bc4097aaSchristos 
637bc4097aaSchristos 
638bc4097aaSchristos /* ------------------------------------------------------------------------ */
639bc4097aaSchristos /* Function:    ipf_pool_exists                                             */
640bc4097aaSchristos /* Returns:     int      - 0 = success, else error                          */
641bc4097aaSchristos /* Parameters:  softp(I) - pointer to soft context pool information         */
642bc4097aaSchristos /*              unit(I)  - ipfilter device to which we are working on       */
643bc4097aaSchristos /*              name(I)  - name of the pool                                 */
644bc4097aaSchristos /*                                                                          */
645bc4097aaSchristos /* Find a matching pool inside the collection of pools for a particular     */
646bc4097aaSchristos /* device, indicated by the unit number.                                    */
647bc4097aaSchristos /* ------------------------------------------------------------------------ */
648bc4097aaSchristos static void *
ipf_pool_exists(softp,unit,name)649bc4097aaSchristos ipf_pool_exists(softp, unit, name)
650bc4097aaSchristos 	ipf_pool_softc_t *softp;
651bc4097aaSchristos 	int unit;
652bc4097aaSchristos 	char *name;
653bc4097aaSchristos {
654bc4097aaSchristos 	ip_pool_t *p;
655bc4097aaSchristos 	int i;
656bc4097aaSchristos 
657bc4097aaSchristos 	if (unit == IPL_LOGALL) {
658bc4097aaSchristos 		for (i = 0; i <= LOOKUP_POOL_MAX; i++) {
659bc4097aaSchristos 			for (p = softp->ipf_pool_list[i]; p != NULL;
660bc4097aaSchristos 			     p = p->ipo_next) {
661bc4097aaSchristos 				if (strncmp(p->ipo_name, name,
662bc4097aaSchristos 					    sizeof(p->ipo_name)) == 0)
663bc4097aaSchristos 					break;
664bc4097aaSchristos 			}
665bc4097aaSchristos 			if (p != NULL)
666bc4097aaSchristos 				break;
667bc4097aaSchristos 		}
668bc4097aaSchristos 	} else {
669bc4097aaSchristos 		for (p = softp->ipf_pool_list[unit + 1]; p != NULL;
670bc4097aaSchristos 		     p = p->ipo_next)
671bc4097aaSchristos 			if (strncmp(p->ipo_name, name,
672bc4097aaSchristos 				    sizeof(p->ipo_name)) == 0)
673bc4097aaSchristos 				break;
674bc4097aaSchristos 	}
675bc4097aaSchristos 	return p;
676bc4097aaSchristos }
677bc4097aaSchristos 
678bc4097aaSchristos 
679bc4097aaSchristos /* ------------------------------------------------------------------------ */
680bc4097aaSchristos /* Function:    ipf_pool_find                                               */
681bc4097aaSchristos /* Returns:     int    - 0 = success, else error                            */
682bc4097aaSchristos /* Parameters:  arg(I)  - pointer to local context to use                   */
683bc4097aaSchristos /*              unit(I) - ipfilter device to which we are working on        */
684bc4097aaSchristos /*              name(I)  - name of the pool                                 */
685bc4097aaSchristos /*                                                                          */
686bc4097aaSchristos /* Find a matching pool inside the collection of pools for a particular     */
687bc4097aaSchristos /* device, indicated by the unit number.  If it is marked for deletion then */
688bc4097aaSchristos /* pretend it does not exist.                                               */
689bc4097aaSchristos /* ------------------------------------------------------------------------ */
690bc4097aaSchristos static void *
ipf_pool_find(arg,unit,name)691bc4097aaSchristos ipf_pool_find(arg, unit, name)
692bc4097aaSchristos 	void *arg;
693bc4097aaSchristos 	int unit;
694bc4097aaSchristos 	char *name;
695bc4097aaSchristos {
696bc4097aaSchristos 	ipf_pool_softc_t *softp = arg;
697bc4097aaSchristos 	ip_pool_t *p;
698bc4097aaSchristos 
699bc4097aaSchristos 	p = ipf_pool_exists(softp, unit, name);
700bc4097aaSchristos 	if ((p != NULL) && (p->ipo_flags & IPOOL_DELETE))
701bc4097aaSchristos 		return NULL;
702bc4097aaSchristos 
703bc4097aaSchristos 	return p;
704bc4097aaSchristos }
705bc4097aaSchristos 
706bc4097aaSchristos 
707bc4097aaSchristos /* ------------------------------------------------------------------------ */
708bc4097aaSchristos /* Function:    ipf_pool_select_add_ref                                     */
709bc4097aaSchristos /* Returns:     int - 0 = success, else error                               */
710bc4097aaSchristos /* Parameters:  arg(I)  - pointer to local context to use                   */
711bc4097aaSchristos /*              unit(I) - ipfilter device to which we are working on        */
712bc4097aaSchristos /*              name(I)  - name of the pool                                 */
713bc4097aaSchristos /*                                                                          */
714bc4097aaSchristos /* ------------------------------------------------------------------------ */
715bc4097aaSchristos static void *
ipf_pool_select_add_ref(arg,unit,name)716bc4097aaSchristos ipf_pool_select_add_ref(arg, unit, name)
717bc4097aaSchristos 	void *arg;
718bc4097aaSchristos 	int unit;
719bc4097aaSchristos 	char *name;
720bc4097aaSchristos {
721bc4097aaSchristos 	ip_pool_t *p;
722bc4097aaSchristos 
723bc4097aaSchristos 	p = ipf_pool_find(arg, -1, name);
724bc4097aaSchristos 	if (p == NULL)
725bc4097aaSchristos 		p = ipf_pool_find(arg, unit, name);
726bc4097aaSchristos 	if (p != NULL) {
727bc4097aaSchristos 		ATOMIC_INC32(p->ipo_ref);
728bc4097aaSchristos 	}
729bc4097aaSchristos 	return p;
730bc4097aaSchristos }
731bc4097aaSchristos 
732bc4097aaSchristos 
733bc4097aaSchristos /* ------------------------------------------------------------------------ */
734bc4097aaSchristos /* Function:    ipf_pool_findeq                                             */
735bc4097aaSchristos /* Returns:     int     - 0 = success, else error                           */
736bc4097aaSchristos /* Parameters:  softp(I) - pointer to soft context pool information         */
737bc4097aaSchristos /*              ipo(I)  - pointer to the pool getting the new node.         */
738bc4097aaSchristos /*              addr(I) - pointer to address information to match on        */
739bc4097aaSchristos /*              mask(I) - pointer to the address mask to match              */
740bc4097aaSchristos /*                                                                          */
741bc4097aaSchristos /* Searches for an exact match of an entry in the pool.                     */
742bc4097aaSchristos /* ------------------------------------------------------------------------ */
743bc4097aaSchristos extern void printhostmask __P((int, u_32_t *, u_32_t *));
744bc4097aaSchristos static ip_pool_node_t *
ipf_pool_findeq(softp,ipo,addr,mask)745bc4097aaSchristos ipf_pool_findeq(softp, ipo, addr, mask)
746bc4097aaSchristos 	ipf_pool_softc_t *softp;
747bc4097aaSchristos 	ip_pool_t *ipo;
748bc4097aaSchristos 	addrfamily_t *addr, *mask;
749bc4097aaSchristos {
750bc4097aaSchristos 	ipf_rdx_node_t *n;
751bc4097aaSchristos 
752bc4097aaSchristos 	n = ipo->ipo_head->lookup(ipo->ipo_head, addr, mask);
753bc4097aaSchristos 	return (ip_pool_node_t *)n;
754bc4097aaSchristos }
755bc4097aaSchristos 
756bc4097aaSchristos 
757bc4097aaSchristos /* ------------------------------------------------------------------------ */
758bc4097aaSchristos /* Function:    ipf_pool_search                                             */
759bc4097aaSchristos /* Returns:     int     - 0 == +ve match, -1 == error, 1 == -ve/no match    */
760bc4097aaSchristos /* Parameters:  softc(I) - pointer to soft context main structure           */
761bc4097aaSchristos /*              tptr(I)    - pointer to the pool to search                  */
762bc4097aaSchristos /*              version(I) - IP protocol version (4 or 6)                   */
763bc4097aaSchristos /*              dptr(I)    - pointer to address information                 */
764bc4097aaSchristos /*              bytes(I)   - length of packet                               */
765bc4097aaSchristos /*                                                                          */
766bc4097aaSchristos /* Search the pool for a given address and return a search result.          */
767bc4097aaSchristos /* ------------------------------------------------------------------------ */
768bc4097aaSchristos static int
ipf_pool_search(softc,tptr,ipversion,dptr,bytes)769bc4097aaSchristos ipf_pool_search(softc, tptr, ipversion, dptr, bytes)
770bc4097aaSchristos 	ipf_main_softc_t *softc;
771bc4097aaSchristos 	void *tptr;
772bc4097aaSchristos 	int ipversion;
773bc4097aaSchristos 	void *dptr;
774bc4097aaSchristos 	u_int bytes;
775bc4097aaSchristos {
776bc4097aaSchristos 	ipf_rdx_node_t *rn;
777bc4097aaSchristos 	ip_pool_node_t *m;
778bc4097aaSchristos 	i6addr_t *addr;
779bc4097aaSchristos 	addrfamily_t v;
780bc4097aaSchristos 	ip_pool_t *ipo;
781bc4097aaSchristos 	int rv;
782bc4097aaSchristos 
783bc4097aaSchristos 	ipo = tptr;
784bc4097aaSchristos 	if (ipo == NULL)
785bc4097aaSchristos 		return -1;
786bc4097aaSchristos 
787bc4097aaSchristos 	rv = 1;
788bc4097aaSchristos 	m = NULL;
789bc4097aaSchristos 	addr = (i6addr_t *)dptr;
790bc4097aaSchristos 	bzero(&v, sizeof(v));
791bc4097aaSchristos 
792bc4097aaSchristos 	if (ipversion == 4) {
793bc4097aaSchristos 		v.adf_family = AF_INET;
794c9d5dc6cSdarrenr 		v.adf_len = offsetof(addrfamily_t, adf_addr) +
795c9d5dc6cSdarrenr 			    sizeof(struct in_addr);
796bc4097aaSchristos 		v.adf_addr.in4 = addr->in4;
797bc4097aaSchristos #ifdef USE_INET6
798bc4097aaSchristos 	} else if (ipversion == 6) {
799bc4097aaSchristos 		v.adf_family = AF_INET6;
800c9d5dc6cSdarrenr 		v.adf_len = offsetof(addrfamily_t, adf_addr) +
801c9d5dc6cSdarrenr 			    sizeof(struct in6_addr);
802bc4097aaSchristos 		v.adf_addr.in6 = addr->in6;
803bc4097aaSchristos #endif
804bc4097aaSchristos 	} else
805bc4097aaSchristos 		return -1;
806bc4097aaSchristos 
807bc4097aaSchristos 	READ_ENTER(&softc->ipf_poolrw);
808bc4097aaSchristos 
809bc4097aaSchristos 	rn = ipo->ipo_head->matchaddr(ipo->ipo_head, &v);
810bc4097aaSchristos 
811bc4097aaSchristos 	if ((rn != NULL) && (rn->root == 0)) {
812bc4097aaSchristos 		m = (ip_pool_node_t *)rn;
813bc4097aaSchristos 		ipo->ipo_hits++;
814bc4097aaSchristos 		m->ipn_bytes += bytes;
815bc4097aaSchristos 		m->ipn_hits++;
816bc4097aaSchristos 		rv = m->ipn_info;
817bc4097aaSchristos 	}
818bc4097aaSchristos 	RWLOCK_EXIT(&softc->ipf_poolrw);
819bc4097aaSchristos 	return rv;
820bc4097aaSchristos }
821bc4097aaSchristos 
822bc4097aaSchristos 
823bc4097aaSchristos /* ------------------------------------------------------------------------ */
824bc4097aaSchristos /* Function:    ipf_pool_insert_node                                        */
825bc4097aaSchristos /* Returns:     int      - 0 = success, else error                          */
826bc4097aaSchristos /* Parameters:  softc(I) - pointer to soft context main structure           */
827bc4097aaSchristos /*              softp(I) - pointer to soft context pool information         */
828bc4097aaSchristos /*              ipo(I)   - pointer to the pool getting the new node.        */
829bc4097aaSchristos /*              node(I)  - structure with address/mask to add               */
830bc4097aaSchristos /* Locks:       WRITE(ipf_poolrw)                                           */
831bc4097aaSchristos /*                                                                          */
832bc4097aaSchristos /* Add another node to the pool given by ipo.  The three parameters passed  */
833bc4097aaSchristos /* in (addr, mask, info) shold all be stored in the node.                   */
834bc4097aaSchristos /* ------------------------------------------------------------------------ */
835bc4097aaSchristos static int
ipf_pool_insert_node(softc,softp,ipo,node)836bc4097aaSchristos ipf_pool_insert_node(softc, softp, ipo, node)
837bc4097aaSchristos 	ipf_main_softc_t *softc;
838bc4097aaSchristos 	ipf_pool_softc_t *softp;
839bc4097aaSchristos 	ip_pool_t *ipo;
840bc4097aaSchristos 	struct ip_pool_node *node;
841bc4097aaSchristos {
842bc4097aaSchristos 	ipf_rdx_node_t *rn;
843bc4097aaSchristos 	ip_pool_node_t *x;
844bc4097aaSchristos 
845bc4097aaSchristos 	if ((node->ipn_addr.adf_len > sizeof(*rn)) ||
846bc4097aaSchristos 	    (node->ipn_addr.adf_len < 4)) {
847bc4097aaSchristos 		IPFERROR(70003);
848bc4097aaSchristos 		return EINVAL;
849bc4097aaSchristos 	}
850bc4097aaSchristos 
851bc4097aaSchristos 	if ((node->ipn_mask.adf_len > sizeof(*rn)) ||
852bc4097aaSchristos 	    (node->ipn_mask.adf_len < 4)) {
853bc4097aaSchristos 		IPFERROR(70004);
854bc4097aaSchristos 		return EINVAL;
855bc4097aaSchristos 	}
856bc4097aaSchristos 
857bc4097aaSchristos 	KMALLOC(x, ip_pool_node_t *);
858bc4097aaSchristos 	if (x == NULL) {
859bc4097aaSchristos 		IPFERROR(70002);
860bc4097aaSchristos 		return ENOMEM;
861bc4097aaSchristos 	}
862bc4097aaSchristos 
863bc4097aaSchristos 	*x = *node;
864bc4097aaSchristos 	bzero((char *)x->ipn_nodes, sizeof(x->ipn_nodes));
865bc4097aaSchristos 	x->ipn_owner = ipo;
866bc4097aaSchristos 	x->ipn_hits = 0;
867bc4097aaSchristos 	x->ipn_next = NULL;
868bc4097aaSchristos 	x->ipn_pnext = NULL;
869bc4097aaSchristos 	x->ipn_dnext = NULL;
870bc4097aaSchristos 	x->ipn_pdnext = NULL;
871bc4097aaSchristos 
872bc4097aaSchristos 	if (x->ipn_die != 0) {
873bc4097aaSchristos 		/*
874bc4097aaSchristos 		 * If the new node has a given expiration time, insert it
875bc4097aaSchristos 		 * into the list of expiring nodes with the ones to be
876bc4097aaSchristos 		 * removed first added to the front of the list. The
877bc4097aaSchristos 		 * insertion is O(n) but it is kept sorted for quick scans
878bc4097aaSchristos 		 * at expiration interval checks.
879bc4097aaSchristos 		 */
880bc4097aaSchristos 		ip_pool_node_t *n;
881bc4097aaSchristos 
882bc4097aaSchristos 		x->ipn_die = softc->ipf_ticks + IPF_TTLVAL(x->ipn_die);
883bc4097aaSchristos 		for (n = softp->ipf_node_explist; n != NULL; n = n->ipn_dnext) {
884bc4097aaSchristos 			if (x->ipn_die < n->ipn_die)
885bc4097aaSchristos 				break;
886bc4097aaSchristos 			if (n->ipn_dnext == NULL) {
887bc4097aaSchristos 				/*
888bc4097aaSchristos 				 * We've got to the last node and everything
889bc4097aaSchristos 				 * wanted to be expired before this new node,
890bc4097aaSchristos 				 * so we have to tack it on the end...
891bc4097aaSchristos 				 */
892bc4097aaSchristos 				n->ipn_dnext = x;
893bc4097aaSchristos 				x->ipn_pdnext = &n->ipn_dnext;
894bc4097aaSchristos 				n = NULL;
895bc4097aaSchristos 				break;
896bc4097aaSchristos 			}
897bc4097aaSchristos 		}
898bc4097aaSchristos 
899bc4097aaSchristos 		if (softp->ipf_node_explist == NULL) {
900bc4097aaSchristos 			softp->ipf_node_explist = x;
901bc4097aaSchristos 			x->ipn_pdnext = &softp->ipf_node_explist;
902bc4097aaSchristos 		} else if (n != NULL) {
903bc4097aaSchristos 			x->ipn_dnext = n;
904bc4097aaSchristos 			x->ipn_pdnext = n->ipn_pdnext;
905bc4097aaSchristos 			n->ipn_pdnext = &x->ipn_dnext;
906bc4097aaSchristos 		}
907bc4097aaSchristos 	}
908bc4097aaSchristos 
909bc4097aaSchristos 	rn = ipo->ipo_head->addaddr(ipo->ipo_head, &x->ipn_addr, &x->ipn_mask,
910bc4097aaSchristos 				    x->ipn_nodes);
911bc4097aaSchristos #ifdef	DEBUG_POOL
912bc4097aaSchristos 	printf("Added %p at %p\n", x, rn);
913bc4097aaSchristos #endif
914bc4097aaSchristos 
915bc4097aaSchristos 	if (rn == NULL) {
916bc4097aaSchristos 		KFREE(x);
917bc4097aaSchristos 		IPFERROR(70005);
918bc4097aaSchristos 		return ENOMEM;
919bc4097aaSchristos 	}
920bc4097aaSchristos 
921bc4097aaSchristos 	x->ipn_ref = 1;
922c9d5dc6cSdarrenr 	x->ipn_pnext = ipo->ipo_tail;
923c9d5dc6cSdarrenr 	*ipo->ipo_tail = x;
924c9d5dc6cSdarrenr 	ipo->ipo_tail = &x->ipn_next;
925bc4097aaSchristos 
926bc4097aaSchristos 	softp->ipf_pool_stats.ipls_nodes++;
927bc4097aaSchristos 
928bc4097aaSchristos 	return 0;
929bc4097aaSchristos }
930bc4097aaSchristos 
931bc4097aaSchristos 
932bc4097aaSchristos /* ------------------------------------------------------------------------ */
933bc4097aaSchristos /* Function:    ipf_pool_create                                             */
934bc4097aaSchristos /* Returns:     int      - 0 = success, else error                          */
935bc4097aaSchristos /* Parameters:  softc(I) - pointer to soft context main structure           */
936bc4097aaSchristos /*              softp(I) - pointer to soft context pool information         */
937bc4097aaSchristos /*              op(I)    - pointer to iplookup struct with call details     */
938bc4097aaSchristos /* Locks:       WRITE(ipf_poolrw)                                           */
939bc4097aaSchristos /*                                                                          */
940bc4097aaSchristos /* Creates a new group according to the paramters passed in via the         */
941bc4097aaSchristos /* iplookupop structure.  Does not check to see if the group already exists */
942bc4097aaSchristos /* when being inserted - assume this has already been done.  If the pool is */
943bc4097aaSchristos /* marked as being anonymous, give it a new, unique, identifier.  Call any  */
944bc4097aaSchristos /* other functions required to initialise the structure.                    */
945bc4097aaSchristos /*                                                                          */
946bc4097aaSchristos /* If the structure is flagged for deletion then reset the flag and return, */
947bc4097aaSchristos /* as this likely means we've tried to free a pool that is in use (flush)   */
948bc4097aaSchristos /* and now want to repopulate it with "new" data.                           */
949bc4097aaSchristos /* ------------------------------------------------------------------------ */
950bc4097aaSchristos static int
ipf_pool_create(softc,softp,op)951bc4097aaSchristos ipf_pool_create(softc, softp, op)
952bc4097aaSchristos 	ipf_main_softc_t *softc;
953bc4097aaSchristos 	ipf_pool_softc_t *softp;
954bc4097aaSchristos 	iplookupop_t *op;
955bc4097aaSchristos {
956bc4097aaSchristos 	char name[FR_GROUPLEN];
957bc4097aaSchristos 	int poolnum, unit;
958bc4097aaSchristos 	ip_pool_t *h;
959bc4097aaSchristos 
960bc4097aaSchristos 	unit = op->iplo_unit;
961bc4097aaSchristos 
962bc4097aaSchristos 	if ((op->iplo_arg & LOOKUP_ANON) == 0) {
963bc4097aaSchristos 		h = ipf_pool_exists(softp, unit, op->iplo_name);
964bc4097aaSchristos 		if (h != NULL) {
965bc4097aaSchristos 			if ((h->ipo_flags & IPOOL_DELETE) == 0) {
966bc4097aaSchristos 				IPFERROR(70006);
967bc4097aaSchristos 				return EEXIST;
968bc4097aaSchristos 			}
969bc4097aaSchristos 			h->ipo_flags &= ~IPOOL_DELETE;
970bc4097aaSchristos 			return 0;
971bc4097aaSchristos 		}
972bc4097aaSchristos 	}
973bc4097aaSchristos 
974bc4097aaSchristos 	KMALLOC(h, ip_pool_t *);
975bc4097aaSchristos 	if (h == NULL) {
976bc4097aaSchristos 		IPFERROR(70007);
977bc4097aaSchristos 		return ENOMEM;
978bc4097aaSchristos 	}
979bc4097aaSchristos 	bzero(h, sizeof(*h));
980bc4097aaSchristos 
981bc4097aaSchristos 	if (ipf_rx_inithead(softp->ipf_radix, &h->ipo_head) != 0) {
982bc4097aaSchristos 		KFREE(h);
983bc4097aaSchristos 		IPFERROR(70008);
984bc4097aaSchristos 		return ENOMEM;
985bc4097aaSchristos 	}
986bc4097aaSchristos 
987bc4097aaSchristos 	if ((op->iplo_arg & LOOKUP_ANON) != 0) {
988bc4097aaSchristos 		ip_pool_t *p;
989bc4097aaSchristos 
990bc4097aaSchristos 		h->ipo_flags |= IPOOL_ANON;
991bc4097aaSchristos 		poolnum = LOOKUP_ANON;
992bc4097aaSchristos 
993bc4097aaSchristos #if defined(SNPRINTF) && defined(_KERNEL)
994bc4097aaSchristos 		SNPRINTF(name, sizeof(name), "%x", poolnum);
995bc4097aaSchristos #else
996bc4097aaSchristos 		(void)sprintf(name, "%x", poolnum);
997bc4097aaSchristos #endif
998bc4097aaSchristos 
999bc4097aaSchristos 		for (p = softp->ipf_pool_list[unit + 1]; p != NULL; ) {
1000bc4097aaSchristos 			if (strncmp(name, p->ipo_name,
1001bc4097aaSchristos 				    sizeof(p->ipo_name)) == 0) {
1002bc4097aaSchristos 				poolnum++;
1003bc4097aaSchristos #if defined(SNPRINTF) && defined(_KERNEL)
1004bc4097aaSchristos 				SNPRINTF(name, sizeof(name), "%x", poolnum);
1005bc4097aaSchristos #else
1006bc4097aaSchristos 				(void)sprintf(name, "%x", poolnum);
1007bc4097aaSchristos #endif
1008bc4097aaSchristos 				p = softp->ipf_pool_list[unit + 1];
1009bc4097aaSchristos 			} else
1010bc4097aaSchristos 				p = p->ipo_next;
1011bc4097aaSchristos 		}
1012bc4097aaSchristos 
1013bc4097aaSchristos 		(void)strncpy(h->ipo_name, name, sizeof(h->ipo_name));
1014bc4097aaSchristos 		(void)strncpy(op->iplo_name, name, sizeof(op->iplo_name));
1015bc4097aaSchristos 	} else {
1016bc4097aaSchristos 		(void)strncpy(h->ipo_name, op->iplo_name, sizeof(h->ipo_name));
1017bc4097aaSchristos 	}
1018bc4097aaSchristos 
1019bc4097aaSchristos 	h->ipo_radix = softp->ipf_radix;
1020bc4097aaSchristos 	h->ipo_ref = 1;
1021bc4097aaSchristos 	h->ipo_list = NULL;
1022c9d5dc6cSdarrenr 	h->ipo_tail = &h->ipo_list;
1023bc4097aaSchristos 	h->ipo_unit = unit;
1024bc4097aaSchristos 	h->ipo_next = softp->ipf_pool_list[unit + 1];
1025bc4097aaSchristos 	if (softp->ipf_pool_list[unit + 1] != NULL)
1026bc4097aaSchristos 		softp->ipf_pool_list[unit + 1]->ipo_pnext = &h->ipo_next;
1027bc4097aaSchristos 	h->ipo_pnext = &softp->ipf_pool_list[unit + 1];
1028bc4097aaSchristos 	softp->ipf_pool_list[unit + 1] = h;
1029bc4097aaSchristos 
1030bc4097aaSchristos 	softp->ipf_pool_stats.ipls_pools++;
1031bc4097aaSchristos 
1032bc4097aaSchristos 	return 0;
1033bc4097aaSchristos }
1034bc4097aaSchristos 
1035bc4097aaSchristos 
1036bc4097aaSchristos /* ------------------------------------------------------------------------ */
1037bc4097aaSchristos /* Function:    ipf_pool_remove_node                                        */
1038bc4097aaSchristos /* Returns:     int      - 0 = success, else error                          */
1039bc4097aaSchristos /* Parameters:  softc(I) - pointer to soft context main structure           */
1040bc4097aaSchristos /*              ipo(I)   - pointer to the pool to remove the node from.     */
1041bc4097aaSchristos /*              ipe(I)   - address being deleted as a node                  */
1042bc4097aaSchristos /* Locks:       WRITE(ipf_poolrw)                                           */
1043bc4097aaSchristos /*                                                                          */
1044bc4097aaSchristos /* Remove a node from the pool given by ipo.                                */
1045bc4097aaSchristos /* ------------------------------------------------------------------------ */
1046bc4097aaSchristos static int
ipf_pool_remove_node(softc,softp,ipo,ipe)1047c9d5dc6cSdarrenr ipf_pool_remove_node(softc, softp, ipo, ipe)
1048c9d5dc6cSdarrenr 	ipf_main_softc_t *softc;
1049bc4097aaSchristos 	ipf_pool_softc_t *softp;
1050bc4097aaSchristos 	ip_pool_t *ipo;
1051bc4097aaSchristos 	ip_pool_node_t *ipe;
1052bc4097aaSchristos {
1053c9d5dc6cSdarrenr 	void *ptr;
1054c9d5dc6cSdarrenr 
1055c9d5dc6cSdarrenr 	if (ipo->ipo_tail == &ipe->ipn_next)
1056c9d5dc6cSdarrenr 		ipo->ipo_tail = ipe->ipn_pnext;
1057bc4097aaSchristos 
1058bc4097aaSchristos 	if (ipe->ipn_pnext != NULL)
1059bc4097aaSchristos 		*ipe->ipn_pnext = ipe->ipn_next;
1060bc4097aaSchristos 	if (ipe->ipn_next != NULL)
1061bc4097aaSchristos 		ipe->ipn_next->ipn_pnext = ipe->ipn_pnext;
1062bc4097aaSchristos 
1063bc4097aaSchristos 	if (ipe->ipn_pdnext != NULL)
1064bc4097aaSchristos 		*ipe->ipn_pdnext = ipe->ipn_dnext;
1065bc4097aaSchristos 	if (ipe->ipn_dnext != NULL)
1066bc4097aaSchristos 		ipe->ipn_dnext->ipn_pdnext = ipe->ipn_pdnext;
1067bc4097aaSchristos 
1068c9d5dc6cSdarrenr 	ptr = ipo->ipo_head->deladdr(ipo->ipo_head, &ipe->ipn_addr,
1069c9d5dc6cSdarrenr 				     &ipe->ipn_mask);
1070bc4097aaSchristos 
1071c9d5dc6cSdarrenr 	if (ptr != NULL) {
1072bc4097aaSchristos 		ipf_pool_node_deref(softp, ipe);
1073bc4097aaSchristos 		return 0;
1074bc4097aaSchristos 	}
1075c9d5dc6cSdarrenr 	IPFERROR(70027);
1076c9d5dc6cSdarrenr 	return ESRCH;
1077c9d5dc6cSdarrenr }
1078bc4097aaSchristos 
1079bc4097aaSchristos 
1080bc4097aaSchristos /* ------------------------------------------------------------------------ */
1081bc4097aaSchristos /* Function:    ipf_pool_destroy                                            */
1082bc4097aaSchristos /* Returns:     int    - 0 = success, else error                            */
1083bc4097aaSchristos /* Parameters:  softc(I) - pointer to soft context main structure           */
1084bc4097aaSchristos /*              softp(I) - pointer to soft context pool information         */
1085bc4097aaSchristos /*              unit(I)  - ipfilter device to which we are working on      */
1086bc4097aaSchristos /*              name(I)  - name of the pool                                 */
1087bc4097aaSchristos /* Locks:       WRITE(ipf_poolrw) or WRITE(ipf_global)                      */
1088bc4097aaSchristos /*                                                                          */
1089bc4097aaSchristos /* Search for a pool using paramters passed in and if it's not otherwise    */
1090bc4097aaSchristos /* busy, free it.  If it is busy, clear all of its nodes, mark it for being */
1091bc4097aaSchristos /* deleted and return an error saying it is busy.                           */
1092bc4097aaSchristos /*                                                                          */
1093bc4097aaSchristos /* NOTE: Because this function is called out of ipfdetach() where ipf_poolrw*/
1094bc4097aaSchristos /* may not be initialised, we can't use an ASSERT to enforce the locking    */
1095bc4097aaSchristos /* assertion that one of the two (ipf_poolrw,ipf_global) is held.           */
1096bc4097aaSchristos /* ------------------------------------------------------------------------ */
1097bc4097aaSchristos static int
ipf_pool_destroy(softc,softp,unit,name)1098bc4097aaSchristos ipf_pool_destroy(softc, softp, unit, name)
1099bc4097aaSchristos 	ipf_main_softc_t *softc;
1100bc4097aaSchristos 	ipf_pool_softc_t *softp;
1101bc4097aaSchristos 	int unit;
1102bc4097aaSchristos 	char *name;
1103bc4097aaSchristos {
1104bc4097aaSchristos 	ip_pool_t *ipo;
1105bc4097aaSchristos 
1106bc4097aaSchristos 	ipo = ipf_pool_exists(softp, unit, name);
1107bc4097aaSchristos 	if (ipo == NULL) {
1108bc4097aaSchristos 		IPFERROR(70009);
1109bc4097aaSchristos 		return ESRCH;
1110bc4097aaSchristos 	}
1111bc4097aaSchristos 
1112bc4097aaSchristos 	if (ipo->ipo_ref != 1) {
1113c9d5dc6cSdarrenr 		ipf_pool_clearnodes(softc, softp, ipo);
1114bc4097aaSchristos 		ipo->ipo_flags |= IPOOL_DELETE;
1115bc4097aaSchristos 		return 0;
1116bc4097aaSchristos 	}
1117bc4097aaSchristos 
1118c9d5dc6cSdarrenr 	ipf_pool_free(softc, softp, ipo);
1119bc4097aaSchristos 	return 0;
1120bc4097aaSchristos }
1121bc4097aaSchristos 
1122bc4097aaSchristos 
1123bc4097aaSchristos /* ------------------------------------------------------------------------ */
1124bc4097aaSchristos /* Function:    ipf_pool_flush                                              */
1125bc4097aaSchristos /* Returns:     int    - number of pools deleted                            */
1126bc4097aaSchristos /* Parameters:  softc(I) - pointer to soft context main structure           */
1127bc4097aaSchristos /*              arg(I)   - pointer to local context to use                  */
1128bc4097aaSchristos /*              fp(I)    - which pool(s) to flush                           */
1129bc4097aaSchristos /* Locks:       WRITE(ipf_poolrw) or WRITE(ipf_global)                      */
1130bc4097aaSchristos /*                                                                          */
1131bc4097aaSchristos /* Free all pools associated with the device that matches the unit number   */
1132bc4097aaSchristos /* passed in with operation.                                                */
1133bc4097aaSchristos /*                                                                          */
1134bc4097aaSchristos /* NOTE: Because this function is called out of ipfdetach() where ipf_poolrw*/
1135bc4097aaSchristos /* may not be initialised, we can't use an ASSERT to enforce the locking    */
1136bc4097aaSchristos /* assertion that one of the two (ipf_poolrw,ipf_global) is held.           */
1137bc4097aaSchristos /* ------------------------------------------------------------------------ */
1138bc4097aaSchristos static size_t
ipf_pool_flush(softc,arg,fp)1139bc4097aaSchristos ipf_pool_flush(softc, arg, fp)
1140bc4097aaSchristos 	ipf_main_softc_t *softc;
1141bc4097aaSchristos 	void *arg;
1142bc4097aaSchristos 	iplookupflush_t *fp;
1143bc4097aaSchristos {
1144bc4097aaSchristos 	ipf_pool_softc_t *softp = arg;
1145bc4097aaSchristos 	int i, num = 0, unit, err;
1146bc4097aaSchristos 	ip_pool_t *p, *q;
1147bc4097aaSchristos 
1148bc4097aaSchristos 	unit = fp->iplf_unit;
1149bc4097aaSchristos 	for (i = -1; i <= IPL_LOGMAX; i++) {
1150bc4097aaSchristos 		if (unit != IPLT_ALL && i != unit)
1151bc4097aaSchristos 			continue;
1152bc4097aaSchristos 		for (q = softp->ipf_pool_list[i + 1]; (p = q) != NULL; ) {
1153bc4097aaSchristos 			q = p->ipo_next;
1154bc4097aaSchristos 			err = ipf_pool_destroy(softc, softp, i, p->ipo_name);
1155bc4097aaSchristos 			if (err == 0)
1156bc4097aaSchristos 				num++;
1157bc4097aaSchristos 		}
1158bc4097aaSchristos 	}
1159bc4097aaSchristos 	return num;
1160bc4097aaSchristos }
1161bc4097aaSchristos 
1162bc4097aaSchristos 
1163bc4097aaSchristos /* ------------------------------------------------------------------------ */
1164bc4097aaSchristos /* Function:    ipf_pool_free                                               */
1165bc4097aaSchristos /* Returns:     void                                                        */
1166c9d5dc6cSdarrenr /* Parameters:  softc(I) - pointer to soft context main structure           */
1167c9d5dc6cSdarrenr /*              softp(I) - pointer to soft context pool information         */
1168bc4097aaSchristos /*              ipo(I) - pointer to pool structure                          */
1169bc4097aaSchristos /* Locks:       WRITE(ipf_poolrw) or WRITE(ipf_global)                      */
1170bc4097aaSchristos /*                                                                          */
1171bc4097aaSchristos /* Deletes the pool strucutre passed in from the list of pools and deletes  */
1172bc4097aaSchristos /* all of the address information stored in it, including any tree data     */
1173bc4097aaSchristos /* structures also allocated.                                               */
1174bc4097aaSchristos /*                                                                          */
1175bc4097aaSchristos /* NOTE: Because this function is called out of ipfdetach() where ipf_poolrw*/
1176bc4097aaSchristos /* may not be initialised, we can't use an ASSERT to enforce the locking    */
1177bc4097aaSchristos /* assertion that one of the two (ipf_poolrw,ipf_global) is held.           */
1178bc4097aaSchristos /* ------------------------------------------------------------------------ */
1179bc4097aaSchristos static void
ipf_pool_free(softc,softp,ipo)1180c9d5dc6cSdarrenr ipf_pool_free(softc, softp, ipo)
1181c9d5dc6cSdarrenr 	ipf_main_softc_t *softc;
1182bc4097aaSchristos 	ipf_pool_softc_t *softp;
1183bc4097aaSchristos 	ip_pool_t *ipo;
1184bc4097aaSchristos {
1185bc4097aaSchristos 
1186c9d5dc6cSdarrenr 	ipf_pool_clearnodes(softc, softp, ipo);
1187bc4097aaSchristos 
1188bc4097aaSchristos 	if (ipo->ipo_next != NULL)
1189bc4097aaSchristos 		ipo->ipo_next->ipo_pnext = ipo->ipo_pnext;
1190bc4097aaSchristos 	*ipo->ipo_pnext = ipo->ipo_next;
1191bc4097aaSchristos 	ipf_rx_freehead(ipo->ipo_head);
1192bc4097aaSchristos 	KFREE(ipo);
1193bc4097aaSchristos 
1194bc4097aaSchristos 	softp->ipf_pool_stats.ipls_pools--;
1195bc4097aaSchristos }
1196bc4097aaSchristos 
1197bc4097aaSchristos 
1198bc4097aaSchristos /* ------------------------------------------------------------------------ */
1199bc4097aaSchristos /* Function:    ipf_pool_clearnodes                                         */
1200bc4097aaSchristos /* Returns:     void                                                        */
1201c9d5dc6cSdarrenr /* Parameters:  softc(I) - pointer to soft context main structure           */
1202c9d5dc6cSdarrenr /*              softp(I) - pointer to soft context pool information         */
1203bc4097aaSchristos /*              ipo(I)   - pointer to pool structure                        */
1204bc4097aaSchristos /* Locks:       WRITE(ipf_poolrw) or WRITE(ipf_global)                      */
1205bc4097aaSchristos /*                                                                          */
1206bc4097aaSchristos /* Deletes all nodes stored in a pool structure.                            */
1207bc4097aaSchristos /* ------------------------------------------------------------------------ */
1208bc4097aaSchristos static void
ipf_pool_clearnodes(softc,softp,ipo)1209c9d5dc6cSdarrenr ipf_pool_clearnodes(softc, softp, ipo)
1210c9d5dc6cSdarrenr 	ipf_main_softc_t *softc;
1211bc4097aaSchristos 	ipf_pool_softc_t *softp;
1212bc4097aaSchristos 	ip_pool_t *ipo;
1213bc4097aaSchristos {
1214bc4097aaSchristos 	ip_pool_node_t *n, **next;
1215bc4097aaSchristos 
1216c9d5dc6cSdarrenr 	for (next = &ipo->ipo_list; (n = *next) != NULL; )
1217c9d5dc6cSdarrenr 		ipf_pool_remove_node(softc, softp, ipo, n);
1218bc4097aaSchristos 
1219bc4097aaSchristos 	ipo->ipo_list = NULL;
1220bc4097aaSchristos }
1221bc4097aaSchristos 
1222bc4097aaSchristos 
1223bc4097aaSchristos /* ------------------------------------------------------------------------ */
1224bc4097aaSchristos /* Function:    ipf_pool_deref                                              */
1225bc4097aaSchristos /* Returns:     void                                                        */
1226bc4097aaSchristos /* Parameters:  softc(I) - pointer to soft context main structure           */
1227bc4097aaSchristos /*              arg(I)   - pointer to local context to use                  */
1228bc4097aaSchristos /*              pool(I)  - pointer to pool structure                        */
1229bc4097aaSchristos /* Locks:       WRITE(ipf_poolrw)                                           */
1230bc4097aaSchristos /*                                                                          */
1231bc4097aaSchristos /* Drop the number of known references to this pool structure by one and if */
1232bc4097aaSchristos /* we arrive at zero known references, free it.                             */
1233bc4097aaSchristos /* ------------------------------------------------------------------------ */
1234bc4097aaSchristos static int
ipf_pool_deref(softc,arg,pool)1235bc4097aaSchristos ipf_pool_deref(softc, arg, pool)
1236bc4097aaSchristos 	ipf_main_softc_t *softc;
1237bc4097aaSchristos 	void *arg, *pool;
1238bc4097aaSchristos {
1239bc4097aaSchristos 	ip_pool_t *ipo = pool;
1240bc4097aaSchristos 
1241bc4097aaSchristos 	ipo->ipo_ref--;
1242bc4097aaSchristos 
1243bc4097aaSchristos 	if (ipo->ipo_ref == 0)
1244c9d5dc6cSdarrenr 		ipf_pool_free(softc, arg, ipo);
1245bc4097aaSchristos 
1246bc4097aaSchristos 	else if ((ipo->ipo_ref == 1) && (ipo->ipo_flags & IPOOL_DELETE))
1247bc4097aaSchristos 		ipf_pool_destroy(softc, arg, ipo->ipo_unit, ipo->ipo_name);
1248bc4097aaSchristos 
1249bc4097aaSchristos 	return 0;
1250bc4097aaSchristos }
1251bc4097aaSchristos 
1252bc4097aaSchristos 
1253bc4097aaSchristos /* ------------------------------------------------------------------------ */
1254bc4097aaSchristos /* Function:    ipf_pool_node_deref                                         */
1255bc4097aaSchristos /* Returns:     void                                                        */
1256bc4097aaSchristos /* Parameters:  softp(I) - pointer to soft context pool information         */
1257bc4097aaSchristos /*              ipn(I)   - pointer to pool structure                        */
1258bc4097aaSchristos /* Locks:       WRITE(ipf_poolrw)                                           */
1259bc4097aaSchristos /*                                                                          */
1260bc4097aaSchristos /* Drop a reference to the pool node passed in and if we're the last, free  */
1261bc4097aaSchristos /* it all up and adjust the stats accordingly.                              */
1262bc4097aaSchristos /* ------------------------------------------------------------------------ */
1263bc4097aaSchristos static void
ipf_pool_node_deref(softp,ipn)1264bc4097aaSchristos ipf_pool_node_deref(softp, ipn)
1265bc4097aaSchristos 	ipf_pool_softc_t *softp;
1266bc4097aaSchristos 	ip_pool_node_t *ipn;
1267bc4097aaSchristos {
1268bc4097aaSchristos 
1269bc4097aaSchristos 	ipn->ipn_ref--;
1270bc4097aaSchristos 
1271bc4097aaSchristos 	if (ipn->ipn_ref == 0) {
1272bc4097aaSchristos 		KFREE(ipn);
1273bc4097aaSchristos 		softp->ipf_pool_stats.ipls_nodes--;
1274bc4097aaSchristos 	}
1275bc4097aaSchristos }
1276bc4097aaSchristos 
1277bc4097aaSchristos 
1278bc4097aaSchristos /* ------------------------------------------------------------------------ */
1279bc4097aaSchristos /* Function:    ipf_pool_iter_next                                          */
1280bc4097aaSchristos /* Returns:     void                                                        */
1281bc4097aaSchristos /* Parameters:  softc(I) - pointer to soft context main structure           */
1282bc4097aaSchristos /*              arg(I)   - pointer to local context to use                  */
1283bc4097aaSchristos /*              token(I) - pointer to pool structure                        */
1284bc4097aaSchristos /*              ilp(IO)  - pointer to pool iterating structure              */
1285bc4097aaSchristos /*                                                                          */
1286bc4097aaSchristos /* ------------------------------------------------------------------------ */
1287bc4097aaSchristos static int
ipf_pool_iter_next(softc,arg,token,ilp)1288bc4097aaSchristos ipf_pool_iter_next(softc, arg, token, ilp)
1289bc4097aaSchristos 	ipf_main_softc_t *softc;
1290bc4097aaSchristos 	void *arg;
1291bc4097aaSchristos 	ipftoken_t *token;
1292bc4097aaSchristos 	ipflookupiter_t *ilp;
1293bc4097aaSchristos {
1294bc4097aaSchristos 	ipf_pool_softc_t *softp = arg;
1295bc4097aaSchristos 	ip_pool_node_t *node, zn, *nextnode;
1296bc4097aaSchristos 	ip_pool_t *ipo, zp, *nextipo;
1297bc4097aaSchristos 	void *pnext;
1298bc4097aaSchristos 	int err;
1299bc4097aaSchristos 
1300bc4097aaSchristos 	err = 0;
1301bc4097aaSchristos 	node = NULL;
1302bc4097aaSchristos 	nextnode = NULL;
1303bc4097aaSchristos 	ipo = NULL;
1304bc4097aaSchristos 	nextipo = NULL;
1305bc4097aaSchristos 
1306bc4097aaSchristos 	READ_ENTER(&softc->ipf_poolrw);
1307bc4097aaSchristos 
1308bc4097aaSchristos 	switch (ilp->ili_otype)
1309bc4097aaSchristos 	{
1310bc4097aaSchristos 	case IPFLOOKUPITER_LIST :
1311bc4097aaSchristos 		ipo = token->ipt_data;
1312bc4097aaSchristos 		if (ipo == NULL) {
1313bc4097aaSchristos 			nextipo = softp->ipf_pool_list[(int)ilp->ili_unit + 1];
1314bc4097aaSchristos 		} else {
1315bc4097aaSchristos 			nextipo = ipo->ipo_next;
1316bc4097aaSchristos 		}
1317bc4097aaSchristos 
1318bc4097aaSchristos 		if (nextipo != NULL) {
1319bc4097aaSchristos 			ATOMIC_INC32(nextipo->ipo_ref);
1320bc4097aaSchristos 			token->ipt_data = nextipo;
1321bc4097aaSchristos 		} else {
1322bc4097aaSchristos 			bzero((char *)&zp, sizeof(zp));
1323bc4097aaSchristos 			nextipo = &zp;
1324bc4097aaSchristos 			token->ipt_data = NULL;
1325bc4097aaSchristos 		}
1326bc4097aaSchristos 		pnext = nextipo->ipo_next;
1327bc4097aaSchristos 		break;
1328bc4097aaSchristos 
1329bc4097aaSchristos 	case IPFLOOKUPITER_NODE :
1330bc4097aaSchristos 		node = token->ipt_data;
1331bc4097aaSchristos 		if (node == NULL) {
1332bc4097aaSchristos 			ipo = ipf_pool_exists(arg, ilp->ili_unit,
1333bc4097aaSchristos 					      ilp->ili_name);
1334bc4097aaSchristos 			if (ipo == NULL) {
1335bc4097aaSchristos 				IPFERROR(70010);
1336bc4097aaSchristos 				err = ESRCH;
1337bc4097aaSchristos 			} else {
1338bc4097aaSchristos 				nextnode = ipo->ipo_list;
1339bc4097aaSchristos 				ipo = NULL;
1340bc4097aaSchristos 			}
1341bc4097aaSchristos 		} else {
1342bc4097aaSchristos 			nextnode = node->ipn_next;
1343bc4097aaSchristos 		}
1344bc4097aaSchristos 
1345bc4097aaSchristos 		if (nextnode != NULL) {
1346bc4097aaSchristos 			ATOMIC_INC32(nextnode->ipn_ref);
1347bc4097aaSchristos 			token->ipt_data = nextnode;
1348bc4097aaSchristos 		} else {
1349bc4097aaSchristos 			bzero((char *)&zn, sizeof(zn));
1350bc4097aaSchristos 			nextnode = &zn;
1351bc4097aaSchristos 			token->ipt_data = NULL;
1352bc4097aaSchristos 		}
1353bc4097aaSchristos 		pnext = nextnode->ipn_next;
1354bc4097aaSchristos 		break;
1355bc4097aaSchristos 
1356bc4097aaSchristos 	default :
1357bc4097aaSchristos 		IPFERROR(70011);
1358bc4097aaSchristos 		pnext = NULL;
1359bc4097aaSchristos 		err = EINVAL;
1360bc4097aaSchristos 		break;
1361bc4097aaSchristos 	}
1362bc4097aaSchristos 
1363bc4097aaSchristos 	RWLOCK_EXIT(&softc->ipf_poolrw);
1364bc4097aaSchristos 	if (err != 0)
1365bc4097aaSchristos 		return err;
1366bc4097aaSchristos 
1367bc4097aaSchristos 	switch (ilp->ili_otype)
1368bc4097aaSchristos 	{
1369bc4097aaSchristos 	case IPFLOOKUPITER_LIST :
1370bc4097aaSchristos 		err = COPYOUT(nextipo, ilp->ili_data, sizeof(*nextipo));
1371bc4097aaSchristos 		if (err != 0)  {
1372bc4097aaSchristos 			IPFERROR(70012);
1373bc4097aaSchristos 			err = EFAULT;
1374bc4097aaSchristos 		}
1375bc4097aaSchristos 		if (ipo != NULL) {
1376bc4097aaSchristos 			WRITE_ENTER(&softc->ipf_poolrw);
1377bc4097aaSchristos 			ipf_pool_deref(softc, softp, ipo);
1378bc4097aaSchristos 			RWLOCK_EXIT(&softc->ipf_poolrw);
1379bc4097aaSchristos 		}
1380bc4097aaSchristos 		break;
1381bc4097aaSchristos 
1382bc4097aaSchristos 	case IPFLOOKUPITER_NODE :
1383bc4097aaSchristos 		err = COPYOUT(nextnode, ilp->ili_data, sizeof(*nextnode));
1384bc4097aaSchristos 		if (err != 0) {
1385bc4097aaSchristos 			IPFERROR(70013);
1386bc4097aaSchristos 			err = EFAULT;
1387bc4097aaSchristos 		}
1388bc4097aaSchristos 		if (node != NULL) {
1389bc4097aaSchristos 			WRITE_ENTER(&softc->ipf_poolrw);
1390bc4097aaSchristos 			ipf_pool_node_deref(softp, node);
1391bc4097aaSchristos 			RWLOCK_EXIT(&softc->ipf_poolrw);
1392bc4097aaSchristos 		}
1393bc4097aaSchristos 		break;
1394bc4097aaSchristos 	}
1395bc4097aaSchristos 	if (pnext == NULL)
1396bc4097aaSchristos 		ipf_token_mark_complete(token);
1397bc4097aaSchristos 
1398bc4097aaSchristos 	return err;
1399bc4097aaSchristos }
1400bc4097aaSchristos 
1401bc4097aaSchristos 
1402bc4097aaSchristos /* ------------------------------------------------------------------------ */
1403bc4097aaSchristos /* Function:    ipf_pool_iterderef                                          */
1404bc4097aaSchristos /* Returns:     void                                                        */
1405bc4097aaSchristos /* Parameters:  softc(I) - pointer to soft context main structure           */
1406bc4097aaSchristos /*              arg(I)   - pointer to local context to use                  */
1407bc4097aaSchristos /*              unit(I)  - ipfilter device to which we are working on       */
1408bc4097aaSchristos /* Locks:       WRITE(ipf_poolrw)                                           */
1409bc4097aaSchristos /*                                                                          */
1410bc4097aaSchristos /* ------------------------------------------------------------------------ */
1411bc4097aaSchristos static int
ipf_pool_iter_deref(softc,arg,otype,unit,data)1412bc4097aaSchristos ipf_pool_iter_deref(softc, arg, otype, unit, data)
1413bc4097aaSchristos 	ipf_main_softc_t *softc;
1414bc4097aaSchristos 	void *arg;
1415bc4097aaSchristos 	int otype;
1416bc4097aaSchristos 	int unit;
1417bc4097aaSchristos 	void *data;
1418bc4097aaSchristos {
1419bc4097aaSchristos 	ipf_pool_softc_t *softp = arg;
1420bc4097aaSchristos 
1421bc4097aaSchristos 	if (data == NULL)
1422bc4097aaSchristos 		return EINVAL;
1423bc4097aaSchristos 
1424bc4097aaSchristos 	if (unit < 0 || unit > IPL_LOGMAX)
1425bc4097aaSchristos 		return EINVAL;
1426bc4097aaSchristos 
1427bc4097aaSchristos 	switch (otype)
1428bc4097aaSchristos 	{
1429bc4097aaSchristos 	case IPFLOOKUPITER_LIST :
1430bc4097aaSchristos 		ipf_pool_deref(softc, softp, (ip_pool_t *)data);
1431bc4097aaSchristos 		break;
1432bc4097aaSchristos 
1433bc4097aaSchristos 	case IPFLOOKUPITER_NODE :
1434bc4097aaSchristos 		ipf_pool_node_deref(softp, (ip_pool_node_t *)data);
1435bc4097aaSchristos 		break;
1436bc4097aaSchristos 	default :
1437bc4097aaSchristos 		break;
1438bc4097aaSchristos 	}
1439bc4097aaSchristos 
1440bc4097aaSchristos 	return 0;
1441bc4097aaSchristos }
1442bc4097aaSchristos 
1443bc4097aaSchristos 
1444bc4097aaSchristos /* ------------------------------------------------------------------------ */
1445bc4097aaSchristos /* Function:    ipf_pool_expire                                             */
1446bc4097aaSchristos /* Returns:     Nil                                                         */
1447bc4097aaSchristos /* Parameters:  softc(I) - pointer to soft context main structure           */
1448bc4097aaSchristos /*              arg(I)   - pointer to local context to use                  */
1449bc4097aaSchristos /*                                                                          */
1450bc4097aaSchristos /* At present this function exists just to support temporary addition of    */
1451bc4097aaSchristos /* nodes to the address pool.                                               */
1452bc4097aaSchristos /* ------------------------------------------------------------------------ */
1453bc4097aaSchristos static void
ipf_pool_expire(softc,arg)1454bc4097aaSchristos ipf_pool_expire(softc, arg)
1455bc4097aaSchristos 	ipf_main_softc_t *softc;
1456bc4097aaSchristos 	void *arg;
1457bc4097aaSchristos {
1458bc4097aaSchristos 	ipf_pool_softc_t *softp = arg;
1459bc4097aaSchristos 	ip_pool_node_t *n;
1460bc4097aaSchristos 
1461bc4097aaSchristos 	while ((n = softp->ipf_node_explist) != NULL) {
1462bc4097aaSchristos 		/*
1463bc4097aaSchristos 		 * Because the list is kept sorted on insertion, the fist
1464bc4097aaSchristos 		 * one that dies in the future means no more work to do.
1465bc4097aaSchristos 		 */
1466bc4097aaSchristos 		if (n->ipn_die > softc->ipf_ticks)
1467bc4097aaSchristos 			break;
1468c9d5dc6cSdarrenr 		ipf_pool_remove_node(softc, softp, n->ipn_owner, n);
1469bc4097aaSchristos 	}
1470bc4097aaSchristos }
1471bc4097aaSchristos 
1472bc4097aaSchristos 
1473bc4097aaSchristos 
1474bc4097aaSchristos 
1475bc4097aaSchristos #ifndef _KERNEL
1476bc4097aaSchristos void
ipf_pool_dump(softc,arg)1477bc4097aaSchristos ipf_pool_dump(softc, arg)
1478bc4097aaSchristos 	ipf_main_softc_t *softc;
1479bc4097aaSchristos 	void *arg;
1480bc4097aaSchristos {
1481bc4097aaSchristos 	ipf_pool_softc_t *softp = arg;
1482bc4097aaSchristos 	ip_pool_t *ipl;
1483bc4097aaSchristos 	int i;
1484bc4097aaSchristos 
1485bc4097aaSchristos 	printf("List of configured pools\n");
1486bc4097aaSchristos 	for (i = 0; i <= LOOKUP_POOL_MAX; i++)
1487bc4097aaSchristos 		for (ipl = softp->ipf_pool_list[i]; ipl != NULL;
1488bc4097aaSchristos 		     ipl = ipl->ipo_next)
1489bc4097aaSchristos 			printpool(ipl, bcopywrap, NULL, opts, NULL);
1490bc4097aaSchristos }
1491bc4097aaSchristos #endif
1492