Expand PMF_FN_* macros.
[netbsd-mini2440.git] / dist / ipf / ip_pool.c
blob39c9ce08321f41bf1ebbafb0bbdecd393b4ee5db
1 /* $NetBSD$ */
3 /*
4 * Copyright (C) 1993-2001, 2003 by Darren Reed.
6 * See the IPFILTER.LICENCE file for details on licencing.
8 * Copyright 2008 Sun Microsystems, Inc.
9 */
10 #if defined(KERNEL) || defined(_KERNEL)
11 # undef KERNEL
12 # undef _KERNEL
13 # define KERNEL 1
14 # define _KERNEL 1
15 #endif
16 #if defined(__osf__)
17 # define _PROTO_NET_H_
18 #endif
19 #include <sys/errno.h>
20 #include <sys/types.h>
21 #include <sys/param.h>
22 #include <sys/file.h>
23 #if !defined(_KERNEL) && !defined(__KERNEL__)
24 # include <stdio.h>
25 # include <stdlib.h>
26 # include <string.h>
27 # define _KERNEL
28 # ifdef __OpenBSD__
29 struct file;
30 # endif
31 # include <sys/uio.h>
32 # undef _KERNEL
33 #else
34 # include <sys/systm.h>
35 # if defined(NetBSD) && (__NetBSD_Version__ >= 104000000)
36 # include <sys/proc.h>
37 # endif
38 #endif
39 #include <sys/time.h>
40 #if defined(_KERNEL) && !defined(SOLARIS2)
41 # include <sys/mbuf.h>
42 #endif
43 #if defined(__SVR4) || defined(__svr4__)
44 # include <sys/byteorder.h>
45 # ifdef _KERNEL
46 # include <sys/dditypes.h>
47 # endif
48 # include <sys/stream.h>
49 # include <sys/kmem.h>
50 #endif
51 #if defined(__FreeBSD_version) && (__FreeBSD_version >= 300000)
52 # include <sys/malloc.h>
53 #endif
55 #if defined(SOLARIS2) && !defined(_KERNEL)
56 # include "radix_ipf.h"
57 #endif
58 #if defined(_KERNEL) && (defined(__osf__) || defined(AIX) || \
59 defined(__hpux) || defined(__sgi))
60 # include "radix_ipf_local.h"
61 # define _RADIX_H_
62 #endif
63 #include <sys/socket.h>
64 #include <net/if.h>
65 #include <netinet/in.h>
67 #include "netinet/ip_compat.h"
68 #include "netinet/ip_fil.h"
69 #include "netinet/ip_pool.h"
71 #if defined(IPFILTER_LOOKUP) && defined(_KERNEL) && \
72 ((BSD >= 198911) && !defined(__osf__) && \
73 !defined(__hpux) && !defined(__sgi))
74 static int rn_freenode __P((struct radix_node *, void *));
75 #endif
77 /* END OF INCLUDES */
79 #if !defined(lint)
80 static const char sccsid[] = "@(#)ip_fil.c 2.41 6/5/96 (C) 1993-2000 Darren Reed";
81 static const char rcsid[] = "@(#)Id: ip_pool.c,v 2.55.2.31 2009/07/18 19:05:39 darrenr Exp";
82 #endif
84 #ifdef IPFILTER_LOOKUP
86 # if !defined(RADIX_NODE_HEAD_LOCK) || !defined(RADIX_NODE_HEAD_UNLOCK) || \
87 !defined(_KERNEL)
88 # undef RADIX_NODE_HEAD_LOCK
89 # undef RADIX_NODE_HEAD_UNLOCK
90 # define RADIX_NODE_HEAD_LOCK(x) ;
91 # define RADIX_NODE_HEAD_UNLOCK(x) ;
92 # endif
94 static void ip_pool_clearnodes __P((ip_pool_t *));
95 static void *ip_pool_exists __P((int, char *));
97 ip_pool_stat_t ipoolstat;
98 ipfrwlock_t ip_poolrw;
100 ip_pool_t *ip_pool_list[IPL_LOGSIZE] = { NULL, NULL, NULL, NULL,
101 NULL, NULL, NULL, NULL };
104 #ifdef TEST_POOL
105 void treeprint __P((ip_pool_t *));
108 main(argc, argv)
109 int argc;
110 char *argv[];
112 addrfamily_t a, b;
113 iplookupop_t op;
114 ip_pool_t *ipo;
115 i6addr_t ip;
117 RWLOCK_INIT(&ip_poolrw, "poolrw");
118 ip_pool_init();
120 bzero((char *)&a, sizeof(a));
121 bzero((char *)&b, sizeof(b));
122 bzero((char *)&ip, sizeof(ip));
123 bzero((char *)&op, sizeof(op));
124 strcpy(op.iplo_name, "0");
126 if (ip_pool_create(&op) == 0)
127 ipo = ip_pool_exists(0, "0");
129 a.adf_addr.in4.s_addr = 0x0a010203;
130 b.adf_addr.in4.s_addr = 0xffffffff;
131 ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 1);
132 ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 1);
134 a.adf_addr.in4.s_addr = 0x0a000000;
135 b.adf_addr.in4.s_addr = 0xff000000;
136 ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 0);
137 ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 0);
139 a.adf_addr.in4.s_addr = 0x0a010100;
140 b.adf_addr.in4.s_addr = 0xffffff00;
141 ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 1);
142 ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 1);
144 a.adf_addr.in4.s_addr = 0x0a010200;
145 b.adf_addr.in4.s_addr = 0xffffff00;
146 ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 0);
147 ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 0);
149 a.adf_addr.in4.s_addr = 0x0a010000;
150 b.adf_addr.in4.s_addr = 0xffff0000;
151 ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 1);
152 ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 1);
154 a.adf_addr.in4.s_addr = 0x0a01020f;
155 b.adf_addr.in4.s_addr = 0xffffffff;
156 ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 1);
157 ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 1);
158 #ifdef DEBUG_POOL
159 treeprint(ipo);
160 #endif
161 ip.in4.s_addr = 0x0a00aabb;
162 printf("search(%#x) = %d (0)\n", ip.in4.s_addr,
163 ip_pool_search(ipo, 4, &ip));
165 ip.in4.s_addr = 0x0a000001;
166 printf("search(%#x) = %d (0)\n", ip.in4.s_addr,
167 ip_pool_search(ipo, 4, &ip));
169 ip.in4.s_addr = 0x0a000101;
170 printf("search(%#x) = %d (0)\n", ip.in4.s_addr,
171 ip_pool_search(ipo, 4, &ip));
173 ip.in4.s_addr = 0x0a010001;
174 printf("search(%#x) = %d (1)\n", ip.in4.s_addr,
175 ip_pool_search(ipo, 4, &ip));
177 ip.in4.s_addr = 0x0a010101;
178 printf("search(%#x) = %d (1)\n", ip.in4.s_addr,
179 ip_pool_search(ipo, 4, &ip));
181 ip.in4.s_addr = 0x0a010201;
182 printf("search(%#x) = %d (0)\n", ip.in4.s_addr,
183 ip_pool_search(ipo, 4, &ip));
185 ip.in4.s_addr = 0x0a010203;
186 printf("search(%#x) = %d (1)\n", ip.in4.s_addr,
187 ip_pool_search(ipo, 4, &ip));
189 ip.in4.s_addr = 0x0a01020f;
190 printf("search(%#x) = %d (1)\n", ip.in4.s_addr,
191 ip_pool_search(ipo, 4, &ip));
193 ip.in4.s_addr = 0x0b00aabb;
194 printf("search(%#x) = %d (-1)\n", ip.in4.s_addr,
195 ip_pool_search(ipo, 4, &ip));
197 #ifdef DEBUG_POOL
198 treeprint(ipo);
199 #endif
201 ip_pool_fini();
203 return 0;
207 void
208 treeprint(ipo)
209 ip_pool_t *ipo;
211 ip_pool_node_t *c;
213 for (c = ipo->ipo_list; c != NULL; c = c->ipn_next)
214 printf("Node %p(%s) (%#x/%#x) = %d hits %lu\n",
215 c, c->ipn_name, c->ipn_addr.adf_addr.in4.s_addr,
216 c->ipn_mask.adf_addr.in4.s_addr,
217 c->ipn_info, c->ipn_hits);
219 #endif /* TEST_POOL */
222 /* ------------------------------------------------------------------------ */
223 /* Function: ip_pool_init */
224 /* Returns: int - 0 = success, else error */
225 /* */
226 /* Initialise the routing table data structures where required. */
227 /* ------------------------------------------------------------------------ */
228 int ip_pool_init()
231 bzero((char *)&ipoolstat, sizeof(ipoolstat));
233 #if (!defined(_KERNEL) || !defined(BSD) || (BSD < 199306))
234 rn_init();
235 #endif
236 return 0;
240 /* ------------------------------------------------------------------------ */
241 /* Function: ip_pool_fini */
242 /* Returns: int - 0 = success, else error */
243 /* Locks: WRITE(ipf_global) */
244 /* */
245 /* Clean up all the pool data structures allocated and call the cleanup */
246 /* function for the radix tree that supports the pools. ip_pool_destroy() is*/
247 /* used to delete the pools one by one to ensure they're properly freed up. */
248 /* ------------------------------------------------------------------------ */
249 void ip_pool_fini()
251 ip_pool_t *p, *q;
252 int i;
254 for (i = 0; i <= IPL_LOGMAX; i++) {
255 for (q = ip_pool_list[i]; (p = q) != NULL; ) {
256 q = p->ipo_next;
257 (void) ip_pool_destroy(i, p->ipo_name);
261 #if (!defined(_KERNEL) || !defined(BSD) || (BSD < 199306))
262 rn_fini();
263 #endif
267 /* ------------------------------------------------------------------------ */
268 /* Function: ip_pool_statistics */
269 /* Returns: int - 0 = success, else error */
270 /* Parameters: op(I) - pointer to lookup operation arguments */
271 /* */
272 /* Copy the current statistics out into user space, collecting pool list */
273 /* pointers as appropriate for later use. */
274 /* ------------------------------------------------------------------------ */
275 int ip_pool_statistics(op)
276 iplookupop_t *op;
278 ip_pool_stat_t stats;
279 int unit, i, err = 0;
281 if (op->iplo_size != sizeof(ipoolstat))
282 return EINVAL;
284 bcopy((char *)&ipoolstat, (char *)&stats, sizeof(stats));
285 unit = op->iplo_unit;
286 if (unit == IPL_LOGALL) {
287 for (i = 0; i < IPL_LOGSIZE; i++)
288 stats.ipls_list[i] = ip_pool_list[i];
289 } else if (unit >= 0 && unit < IPL_LOGSIZE) {
290 if (op->iplo_name[0] != '\0')
291 stats.ipls_list[unit] = ip_pool_exists(unit,
292 op->iplo_name);
293 else
294 stats.ipls_list[unit] = ip_pool_list[unit];
295 } else
296 err = EINVAL;
297 if (err == 0)
298 err = COPYOUT(&stats, op->iplo_struct, sizeof(stats));
299 return err;
303 /* ------------------------------------------------------------------------ */
304 /* Function: ip_pool_exists */
305 /* Returns: int - 0 = success, else error */
306 /* Parameters: ipo(I) - pointer to the pool getting the new node. */
307 /* */
308 /* Find a matching pool inside the collection of pools for a particular */
309 /* device, indicated by the unit number. */
310 /* ------------------------------------------------------------------------ */
311 static void *ip_pool_exists(unit, name)
312 int unit;
313 char *name;
315 ip_pool_t *p;
317 for (p = ip_pool_list[unit]; p != NULL; p = p->ipo_next)
318 if (strncmp(p->ipo_name, name, sizeof(p->ipo_name)) == 0)
319 break;
320 return p;
324 /* ------------------------------------------------------------------------ */
325 /* Function: ip_pool_find */
326 /* Returns: int - 0 = success, else error */
327 /* Parameters: ipo(I) - pointer to the pool getting the new node. */
328 /* */
329 /* Find a matching pool inside the collection of pools for a particular */
330 /* device, indicated by the unit number. If it is marked for deletion then */
331 /* pretend it does not exist. */
332 /* ------------------------------------------------------------------------ */
333 void *ip_pool_find(unit, name)
334 int unit;
335 char *name;
337 ip_pool_t *p;
339 p = ip_pool_exists(unit, name);
340 if ((p != NULL) && (p->ipo_flags & IPOOL_DELETE))
341 return NULL;
343 return p;
347 /* ------------------------------------------------------------------------ */
348 /* Function: ip_pool_findeq */
349 /* Returns: int - 0 = success, else error */
350 /* Parameters: ipo(I) - pointer to the pool getting the new node. */
351 /* addr(I) - pointer to address information to delete */
352 /* mask(I) - */
353 /* */
354 /* Searches for an exact match of an entry in the pool. */
355 /* ------------------------------------------------------------------------ */
356 ip_pool_node_t *ip_pool_findeq(ipo, addr, mask)
357 ip_pool_t *ipo;
358 addrfamily_t *addr, *mask;
360 struct radix_node *n;
361 SPL_INT(s);
363 SPL_NET(s);
364 RADIX_NODE_HEAD_LOCK(ipo->ipo_head);
365 n = ipo->ipo_head->rnh_lookup(addr, mask, ipo->ipo_head);
366 RADIX_NODE_HEAD_UNLOCK(ipo->ipo_head);
367 SPL_X(s);
368 return (ip_pool_node_t *)n;
372 /* ------------------------------------------------------------------------ */
373 /* Function: ip_pool_search */
374 /* Returns: int - 0 == +ve match, -1 == error, 1 == -ve/no match */
375 /* Parameters: tptr(I) - pointer to the pool to search */
376 /* version(I) - IP protocol version (4 or 6) */
377 /* dptr(I) - pointer to address information */
378 /* */
379 /* Search the pool for a given address and return a search result. */
380 /* ------------------------------------------------------------------------ */
381 int ip_pool_search(tptr, ipversion, dptr)
382 void *tptr;
383 int ipversion;
384 void *dptr;
386 struct radix_node *rn;
387 ip_pool_node_t *m;
388 i6addr_t *addr;
389 addrfamily_t v;
390 ip_pool_t *ipo;
391 int rv;
393 ipo = tptr;
394 if (ipo == NULL)
395 return -1;
397 rv = 1;
398 m = NULL;
399 addr = (i6addr_t *)dptr;
400 bzero(&v, sizeof(v));
401 v.adf_len = offsetof(addrfamily_t, adf_addr);
403 if (ipversion == 4) {
404 v.adf_len += sizeof(addr->in4);
405 v.adf_addr.in4 = addr->in4;
406 #ifdef USE_INET6
407 } else if (ipversion == 6) {
408 v.adf_len += sizeof(addr->in6);
409 v.adf_addr.in6 = addr->in6;
410 #endif
411 } else
412 return -1;
414 READ_ENTER(&ip_poolrw);
416 RADIX_NODE_HEAD_LOCK(ipo->ipo_head);
417 rn = ipo->ipo_head->rnh_matchaddr(&v, ipo->ipo_head);
418 RADIX_NODE_HEAD_UNLOCK(ipo->ipo_head);
420 if ((rn != NULL) && ((rn->rn_flags & RNF_ROOT) == 0)) {
421 m = (ip_pool_node_t *)rn;
422 ipo->ipo_hits++;
423 m->ipn_hits++;
424 rv = m->ipn_info;
426 RWLOCK_EXIT(&ip_poolrw);
427 return rv;
431 /* ------------------------------------------------------------------------ */
432 /* Function: ip_pool_insert */
433 /* Returns: int - 0 = success, else error */
434 /* Parameters: ipo(I) - pointer to the pool getting the new node. */
435 /* addr(I) - address being added as a node */
436 /* mask(I) - netmask to with the node being added */
437 /* info(I) - extra information to store in this node. */
438 /* Locks: WRITE(ip_poolrw) */
439 /* */
440 /* Add another node to the pool given by ipo. The three parameters passed */
441 /* in (addr, mask, info) shold all be stored in the node. */
442 /* ------------------------------------------------------------------------ */
443 int ip_pool_insert(ipo, addr, mask, info)
444 ip_pool_t *ipo;
445 i6addr_t *addr, *mask;
446 int info;
448 struct radix_node *rn;
449 ip_pool_node_t *x;
451 KMALLOC(x, ip_pool_node_t *);
452 if (x == NULL) {
453 return ENOMEM;
456 bzero(x, sizeof(*x));
458 x->ipn_info = info;
459 (void)strncpy(x->ipn_name, ipo->ipo_name, sizeof(x->ipn_name));
461 bcopy(addr, &x->ipn_addr.adf_addr, sizeof(*addr));
462 x->ipn_addr.adf_len = sizeof(x->ipn_addr);
463 bcopy(mask, &x->ipn_mask.adf_addr, sizeof(*mask));
464 x->ipn_mask.adf_len = sizeof(x->ipn_mask);
466 RADIX_NODE_HEAD_LOCK(ipo->ipo_head);
467 rn = ipo->ipo_head->rnh_addaddr(&x->ipn_addr, &x->ipn_mask,
468 ipo->ipo_head, x->ipn_nodes);
469 RADIX_NODE_HEAD_UNLOCK(ipo->ipo_head);
470 #ifdef DEBUG_POOL
471 printf("Added %p at %p\n", x, rn);
472 #endif
474 if (rn == NULL) {
475 KFREE(x);
476 return ENOMEM;
479 x->ipn_ref = 1;
480 x->ipn_next = ipo->ipo_list;
481 x->ipn_pnext = &ipo->ipo_list;
482 if (ipo->ipo_list != NULL)
483 ipo->ipo_list->ipn_pnext = &x->ipn_next;
484 ipo->ipo_list = x;
486 ipoolstat.ipls_nodes++;
488 return 0;
492 /* ------------------------------------------------------------------------ */
493 /* Function: ip_pool_create */
494 /* Returns: int - 0 = success, else error */
495 /* Parameters: op(I) - pointer to iplookup struct with call details */
496 /* Locks: WRITE(ip_poolrw) */
497 /* */
498 /* Creates a new group according to the paramters passed in via the */
499 /* iplookupop structure. Does not check to see if the group already exists */
500 /* when being inserted - assume this has already been done. If the pool is */
501 /* marked as being anonymous, give it a new, unique, identifier. Call any */
502 /* other functions required to initialise the structure. */
503 /* */
504 /* If the structure is flagged for deletion then reset the flag and return, */
505 /* as this likely means we've tried to free a pool that is in use (flush) */
506 /* and now want to repopulate it with "new" data. */
507 /* ------------------------------------------------------------------------ */
508 int ip_pool_create(op)
509 iplookupop_t *op;
511 char name[FR_GROUPLEN];
512 int poolnum, unit;
513 ip_pool_t *h;
515 unit = op->iplo_unit;
517 if ((op->iplo_arg & LOOKUP_ANON) == 0) {
518 h = ip_pool_exists(unit, op->iplo_name);
519 if (h != NULL) {
520 if ((h->ipo_flags & IPOOL_DELETE) == 0)
521 return EEXIST;
522 h->ipo_flags &= ~IPOOL_DELETE;
523 return 0;
527 KMALLOC(h, ip_pool_t *);
528 if (h == NULL)
529 return ENOMEM;
530 bzero(h, sizeof(*h));
532 if (rn_inithead((void **)&h->ipo_head,
533 offsetof(addrfamily_t, adf_addr) << 3) == 0) {
534 KFREE(h);
535 return ENOMEM;
538 if ((op->iplo_arg & LOOKUP_ANON) != 0) {
539 ip_pool_t *p;
541 h->ipo_flags |= IPOOL_ANON;
542 poolnum = LOOKUP_ANON;
544 #if defined(SNPRINTF) && defined(_KERNEL)
545 SNPRINTF(name, sizeof(name), "%x", poolnum);
546 #else
547 (void)sprintf(name, "%x", poolnum);
548 #endif
550 for (p = ip_pool_list[unit]; p != NULL; ) {
551 if (strncmp(name, p->ipo_name,
552 sizeof(p->ipo_name)) == 0) {
553 poolnum++;
554 #if defined(SNPRINTF) && defined(_KERNEL)
555 SNPRINTF(name, sizeof(name), "%x", poolnum);
556 #else
557 (void)sprintf(name, "%x", poolnum);
558 #endif
559 p = ip_pool_list[unit];
560 } else
561 p = p->ipo_next;
564 (void)strncpy(h->ipo_name, name, sizeof(h->ipo_name));
565 (void)strncpy(op->iplo_name, name, sizeof(op->iplo_name));
566 } else {
567 (void)strncpy(h->ipo_name, op->iplo_name, sizeof(h->ipo_name));
570 h->ipo_ref = 1;
571 h->ipo_list = NULL;
572 h->ipo_unit = unit;
573 h->ipo_next = ip_pool_list[unit];
574 if (ip_pool_list[unit] != NULL)
575 ip_pool_list[unit]->ipo_pnext = &h->ipo_next;
576 h->ipo_pnext = &ip_pool_list[unit];
577 ip_pool_list[unit] = h;
579 ipoolstat.ipls_pools++;
581 return 0;
585 /* ------------------------------------------------------------------------ */
586 /* Function: ip_pool_remove */
587 /* Returns: int - 0 = success, else error */
588 /* Parameters: ipo(I) - pointer to the pool to remove the node from. */
589 /* ipe(I) - address being deleted as a node */
590 /* Locks: WRITE(ip_poolrw) */
591 /* */
592 /* Remove a node from the pool given by ipo. */
593 /* ------------------------------------------------------------------------ */
594 int ip_pool_remove(ipo, ipe)
595 ip_pool_t *ipo;
596 ip_pool_node_t *ipe;
599 if (ipe->ipn_pnext != NULL)
600 *ipe->ipn_pnext = ipe->ipn_next;
601 if (ipe->ipn_next != NULL)
602 ipe->ipn_next->ipn_pnext = ipe->ipn_pnext;
604 RADIX_NODE_HEAD_LOCK(ipo->ipo_head);
605 ipo->ipo_head->rnh_deladdr(&ipe->ipn_addr, &ipe->ipn_mask,
606 ipo->ipo_head);
607 RADIX_NODE_HEAD_UNLOCK(ipo->ipo_head);
609 ip_pool_node_deref(ipe);
611 return 0;
615 /* ------------------------------------------------------------------------ */
616 /* Function: ip_pool_destroy */
617 /* Returns: int - 0 = success, else error */
618 /* Parameters: op(I) - information about the pool to remove */
619 /* Locks: WRITE(ip_poolrw) or WRITE(ipf_global) */
620 /* */
621 /* Search for a pool using paramters passed in and if it's not otherwise */
622 /* busy, free it. If it is busy, clear all of its nodes, mark it for being */
623 /* deleted and return an error saying it is busy. */
624 /* */
625 /* NOTE: Because this function is called out of ipfdetach() where ip_poolrw */
626 /* may not be initialised, we can't use an ASSERT to enforce the locking */
627 /* assertion that one of the two (ip_poolrw,ipf_global) is held. */
628 /* ------------------------------------------------------------------------ */
629 int ip_pool_destroy(unit, name)
630 int unit;
631 char *name;
633 ip_pool_t *ipo;
635 ipo = ip_pool_exists(unit, name);
636 if (ipo == NULL)
637 return ESRCH;
639 if (ipo->ipo_ref != 1) {
640 ip_pool_clearnodes(ipo);
641 ipo->ipo_flags |= IPOOL_DELETE;
642 return 0;
645 ip_pool_free(ipo);
646 return 0;
650 /* ------------------------------------------------------------------------ */
651 /* Function: ip_pool_flush */
652 /* Returns: int - number of pools deleted */
653 /* Parameters: fp(I) - which pool(s) to flush */
654 /* Locks: WRITE(ip_poolrw) or WRITE(ipf_global) */
655 /* */
656 /* Free all pools associated with the device that matches the unit number */
657 /* passed in with operation. */
658 /* */
659 /* NOTE: Because this function is called out of ipfdetach() where ip_poolrw */
660 /* may not be initialised, we can't use an ASSERT to enforce the locking */
661 /* assertion that one of the two (ip_poolrw,ipf_global) is held. */
662 /* ------------------------------------------------------------------------ */
663 int ip_pool_flush(fp)
664 iplookupflush_t *fp;
666 int i, num = 0, unit, err;
667 ip_pool_t *p, *q;
668 iplookupop_t op;
670 unit = fp->iplf_unit;
672 for (i = 0; i <= IPL_LOGMAX; i++) {
673 if (unit != IPLT_ALL && i != unit)
674 continue;
675 for (q = ip_pool_list[i]; (p = q) != NULL; ) {
676 op.iplo_unit = i;
677 (void)strncpy(op.iplo_name, p->ipo_name,
678 sizeof(op.iplo_name));
679 q = p->ipo_next;
680 err = ip_pool_destroy(op.iplo_unit, op.iplo_name);
681 if (err == 0)
682 num++;
683 else
684 break;
687 return num;
691 /* ------------------------------------------------------------------------ */
692 /* Function: ip_pool_free */
693 /* Returns: void */
694 /* Parameters: ipo(I) - pointer to pool structure */
695 /* Locks: WRITE(ip_poolrw) or WRITE(ipf_global) */
696 /* */
697 /* Deletes the pool strucutre passed in from the list of pools and deletes */
698 /* all of the address information stored in it, including any tree data */
699 /* structures also allocated. */
700 /* */
701 /* NOTE: Because this function is called out of ipfdetach() where ip_poolrw */
702 /* may not be initialised, we can't use an ASSERT to enforce the locking */
703 /* assertion that one of the two (ip_poolrw,ipf_global) is held. */
704 /* ------------------------------------------------------------------------ */
705 void ip_pool_free(ipo)
706 ip_pool_t *ipo;
709 ip_pool_clearnodes(ipo);
711 if (ipo->ipo_next != NULL)
712 ipo->ipo_next->ipo_pnext = ipo->ipo_pnext;
713 *ipo->ipo_pnext = ipo->ipo_next;
714 rn_freehead(ipo->ipo_head);
715 KFREE(ipo);
717 ipoolstat.ipls_pools--;
721 /* ------------------------------------------------------------------------ */
722 /* Function: ip_pool_clearnodes */
723 /* Returns: void */
724 /* Parameters: ipo(I) - pointer to pool structure */
725 /* Locks: WRITE(ip_poolrw) or WRITE(ipf_global) */
726 /* */
727 /* Deletes all nodes stored in a pool structure. */
728 /* ------------------------------------------------------------------------ */
729 static void ip_pool_clearnodes(ipo)
730 ip_pool_t *ipo;
732 ip_pool_node_t *n;
734 RADIX_NODE_HEAD_LOCK(ipo->ipo_head);
735 while ((n = ipo->ipo_list) != NULL) {
736 ipo->ipo_head->rnh_deladdr(&n->ipn_addr, &n->ipn_mask,
737 ipo->ipo_head);
739 *n->ipn_pnext = n->ipn_next;
740 if (n->ipn_next)
741 n->ipn_next->ipn_pnext = n->ipn_pnext;
743 KFREE(n);
745 ipoolstat.ipls_nodes--;
747 RADIX_NODE_HEAD_UNLOCK(ipo->ipo_head);
749 ipo->ipo_list = NULL;
753 /* ------------------------------------------------------------------------ */
754 /* Function: ip_pool_deref */
755 /* Returns: void */
756 /* Parameters: ipo(I) - pointer to pool structure */
757 /* Locks: WRITE(ip_poolrw) */
758 /* */
759 /* Drop the number of known references to this pool structure by one and if */
760 /* we arrive at zero known references, free it. */
761 /* ------------------------------------------------------------------------ */
762 void ip_pool_deref(ipo)
763 ip_pool_t *ipo;
766 ipo->ipo_ref--;
768 if (ipo->ipo_ref == 0)
769 ip_pool_free(ipo);
771 else if ((ipo->ipo_ref == 1) && (ipo->ipo_flags & IPOOL_DELETE))
772 ip_pool_destroy(ipo->ipo_unit, ipo->ipo_name);
776 /* ------------------------------------------------------------------------ */
777 /* Function: ip_pool_node_deref */
778 /* Returns: void */
779 /* Parameters: ipn(I) - pointer to pool structure */
780 /* Locks: WRITE(ip_poolrw) */
781 /* */
782 /* Drop a reference to the pool node passed in and if we're the last, free */
783 /* it all up and adjust the stats accordingly. */
784 /* ------------------------------------------------------------------------ */
785 void ip_pool_node_deref(ipn)
786 ip_pool_node_t *ipn;
789 ipn->ipn_ref--;
791 if (ipn->ipn_ref == 0) {
792 KFREE(ipn);
793 ipoolstat.ipls_nodes--;
798 /* ------------------------------------------------------------------------ */
799 /* Function: ip_pool_getnext */
800 /* Returns: void */
801 /* Parameters: token(I) - pointer to pool structure */
802 /* ilp(IO) - pointer to pool iterating structure */
803 /* */
804 /* ------------------------------------------------------------------------ */
805 int ip_pool_getnext(token, ilp)
806 ipftoken_t *token;
807 ipflookupiter_t *ilp;
809 ip_pool_node_t *node, zn, *nextnode;
810 ip_pool_t *ipo, zp, *nextipo;
811 int err;
813 err = 0;
814 node = NULL;
815 nextnode = NULL;
816 ipo = NULL;
817 nextipo = NULL;
819 READ_ENTER(&ip_poolrw);
822 * Get "previous" entry from token. Find next entry to process,
823 * and add reference to it and update the token.
825 switch (ilp->ili_otype)
827 case IPFLOOKUPITER_LIST :
828 ipo = token->ipt_data;
829 if (ipo == NULL) {
830 nextipo = ip_pool_list[(int)ilp->ili_unit];
831 } else {
832 nextipo = ipo->ipo_next;
835 if (nextipo != NULL) {
836 ATOMIC_INC(nextipo->ipo_ref);
837 token->ipt_data = nextipo;
838 } else {
839 bzero((char *)&zp, sizeof(zp));
840 nextipo = &zp;
841 token->ipt_data = NULL;
843 break;
845 case IPFLOOKUPITER_NODE :
846 node = token->ipt_data;
847 if (node == NULL) {
848 ipo = ip_pool_exists(ilp->ili_unit, ilp->ili_name);
849 if (ipo == NULL)
850 err = ESRCH;
851 else {
852 nextnode = ipo->ipo_list;
853 ipo = NULL;
855 } else {
856 nextnode = node->ipn_next;
859 if (nextnode != NULL) {
860 ATOMIC_INC(nextnode->ipn_ref);
861 token->ipt_data = nextnode;
862 } else {
863 bzero((char *)&zn, sizeof(zn));
864 nextnode = &zn;
865 token->ipt_data = NULL;
867 break;
869 default :
870 err = EINVAL;
871 break;
875 * Now that we have ref, it's save to give up lock.
877 RWLOCK_EXIT(&ip_poolrw);
879 if (err != 0)
880 return err;
883 * Copy out the data and update the references and token as needed.
885 switch (ilp->ili_otype)
887 case IPFLOOKUPITER_LIST :
888 err = COPYOUT(nextipo, ilp->ili_data, sizeof(*nextipo));
889 if (err != 0)
890 err = EFAULT;
891 if (token->ipt_data != NULL) {
892 if (ipo != NULL) {
893 WRITE_ENTER(&ip_poolrw);
894 ip_pool_deref(ipo);
895 RWLOCK_EXIT(&ip_poolrw);
897 if (nextipo->ipo_next == NULL)
898 token->ipt_data = NULL;
900 break;
902 case IPFLOOKUPITER_NODE :
903 err = COPYOUT(nextnode, ilp->ili_data, sizeof(*nextnode));
904 if (err != 0)
905 err = EFAULT;
906 if (token->ipt_data != NULL) {
907 if (node != NULL) {
908 WRITE_ENTER(&ip_poolrw);
909 ip_pool_node_deref(node);
910 RWLOCK_EXIT(&ip_poolrw);
912 if (nextnode->ipn_next == NULL)
913 token->ipt_data = NULL;
915 break;
918 return err;
922 /* ------------------------------------------------------------------------ */
923 /* Function: ip_pool_iterderef */
924 /* Returns: void */
925 /* Parameters: ipn(I) - pointer to pool structure */
926 /* Locks: WRITE(ip_poolrw) */
927 /* */
928 /* ------------------------------------------------------------------------ */
929 void ip_pool_iterderef(otype, unit, data)
930 u_int otype;
931 int unit;
932 void *data;
935 if (data == NULL)
936 return;
938 if (unit < 0 || unit > IPL_LOGMAX)
939 return;
941 switch (otype)
943 case IPFLOOKUPITER_LIST :
944 WRITE_ENTER(&ip_poolrw);
945 ip_pool_deref((ip_pool_t *)data);
946 RWLOCK_EXIT(&ip_poolrw);
947 break;
949 case IPFLOOKUPITER_NODE :
950 WRITE_ENTER(&ip_poolrw);
951 ip_pool_node_deref((ip_pool_node_t *)data);
952 RWLOCK_EXIT(&ip_poolrw);
953 break;
954 default :
955 break;
960 # if defined(_KERNEL) && (defined(BSD) && (BSD >= 198911) && \
961 !defined(__osf__) && !defined(__hpux) && !defined(__sgi))
962 static int
963 rn_freenode(struct radix_node *n, void *p)
965 struct radix_node_head *rnh = p;
966 struct radix_node *d;
968 d = rnh->rnh_deladdr(n->rn_key, NULL, rnh);
969 if (d != NULL) {
970 FreeS(d, max_keylen + 2 * sizeof (*d));
972 return 0;
976 void
977 rn_freehead(rnh)
978 struct radix_node_head *rnh;
981 RADIX_NODE_HEAD_LOCK(rnh);
982 # if defined(__NetBSD_Version__) && (__NetBSD_Version__ > 499002000)
983 rn_walktree(rnh, rn_freenode, rnh);
984 # else
985 (*rnh->rnh_walktree)(rnh, rn_freenode, rnh);
986 # endif
988 rnh->rnh_addaddr = NULL;
989 rnh->rnh_deladdr = NULL;
990 rnh->rnh_matchaddr = NULL;
991 rnh->rnh_lookup = NULL;
992 RADIX_NODE_HEAD_UNLOCK(rnh);
994 Free(rnh);
996 # endif
997 #endif /* IPFILTER_LOOKUP */