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__
38struct 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
83static const char sccsid[] = "@(#)ip_fil.c 2.41 6/5/96 (C) 1993-2000 Darren Reed";
84static 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
88typedef 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
96static void ipf_pool_clearnodes(ipf_main_softc_t *, ipf_pool_softc_t *,
97 ip_pool_t *);
98static int ipf_pool_create(ipf_main_softc_t *, ipf_pool_softc_t *, iplookupop_t *);
99static int ipf_pool_deref(ipf_main_softc_t *, void *, void *);
100static int ipf_pool_destroy(ipf_main_softc_t *, ipf_pool_softc_t *, int, char *);
101static void *ipf_pool_exists(ipf_pool_softc_t *, int, char *);
102static void *ipf_pool_find(void *, int, char *);
103static ip_pool_node_t *ipf_pool_findeq(ipf_pool_softc_t *, ip_pool_t *,
104 addrfamily_t *, addrfamily_t *);
105static void ipf_pool_free(ipf_main_softc_t *, ipf_pool_softc_t *, ip_pool_t *);
106static int ipf_pool_insert_node(ipf_main_softc_t *, ipf_pool_softc_t *,
107 ip_pool_t *, struct ip_pool_node *);
108static int ipf_pool_iter_deref(ipf_main_softc_t *, void *, int, int, void *);
109static int ipf_pool_iter_next(ipf_main_softc_t *, void *, ipftoken_t *,
110 ipflookupiter_t *);
111static size_t ipf_pool_flush(ipf_main_softc_t *, void *, iplookupflush_t *);
112static int ipf_pool_node_add(ipf_main_softc_t *, void *, iplookupop_t *,
113 int);
114static int ipf_pool_node_del(ipf_main_softc_t *, void *, iplookupop_t *,
115 int);
116static void ipf_pool_node_deref(ipf_pool_softc_t *, ip_pool_node_t *);
117static int ipf_pool_remove_node(ipf_main_softc_t *, ipf_pool_softc_t *,
118 ip_pool_t *, ip_pool_node_t *);
119static int ipf_pool_search(ipf_main_softc_t *, void *, int,
120 void *, u_int);
121static void *ipf_pool_soft_create(ipf_main_softc_t *);
122static void ipf_pool_soft_destroy(ipf_main_softc_t *, void *);
123static void ipf_pool_soft_fini(ipf_main_softc_t *, void *);
124static int ipf_pool_soft_init(ipf_main_softc_t *, void *);
125static int ipf_pool_stats_get(ipf_main_softc_t *, void *, iplookupop_t *);
126static int ipf_pool_table_add(ipf_main_softc_t *, void *, iplookupop_t *);
127static int ipf_pool_table_del(ipf_main_softc_t *, void *, iplookupop_t *);
128static void *ipf_pool_select_add_ref(void *, int, char *);
129static void ipf_pool_expire(ipf_main_softc_t *, void *);
130
131ipf_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
156void treeprint(ip_pool_t *);
157
158int
159main(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
260void
261treeprint(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/* ------------------------------------------------------------------------ */
282static void *
283ipf_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/* ------------------------------------------------------------------------ */
314static int
315ipf_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/* ------------------------------------------------------------------------ */
336static void
337ipf_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/* ------------------------------------------------------------------------ */
363static void
364ipf_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/* ------------------------------------------------------------------------ */
385static int
386ipf_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/* ------------------------------------------------------------------------ */
476static int
477ipf_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/* ------------------------------------------------------------------------ */
548static int
549ipf_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/* ------------------------------------------------------------------------ */
573static int
574ipf_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/* ------------------------------------------------------------------------ */
590static int
591ipf_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/* ------------------------------------------------------------------------ */
639static void *
640ipf_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/* ------------------------------------------------------------------------ */
678static void *
679ipf_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/* ------------------------------------------------------------------------ */
700static void *
701ipf_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/* ------------------------------------------------------------------------ */
725extern void printhostmask(int, u_32_t *, u_32_t *);
726static ip_pool_node_t *
727ipf_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/* ------------------------------------------------------------------------ */
748static int
749ipf_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/* ------------------------------------------------------------------------ */
811static int
812ipf_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/* ------------------------------------------------------------------------ */
923static int
924ipf_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/* ------------------------------------------------------------------------ */
1009static int
1010ipf_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/* ------------------------------------------------------------------------ */
1057static int
1058ipf_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/* ------------------------------------------------------------------------ */
1095static size_t
1096ipf_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/* ------------------------------------------------------------------------ */
1133static void
1134ipf_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/* ------------------------------------------------------------------------ */
1159static void
1160ipf_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/* ------------------------------------------------------------------------ */
1183static int
1184ipf_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/* ------------------------------------------------------------------------ */
1210static void
1211ipf_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/* ------------------------------------------------------------------------ */
1232static int
1233ipf_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/* ------------------------------------------------------------------------ */
1353static int
1354ipf_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/* ------------------------------------------------------------------------ */
1391static void
1392ipf_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
1412void
1413ipf_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