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