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