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