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