Expand PMF_FN_* macros.
[netbsd-mini2440.git] / sys / dist / ipf / netinet / ip_pool.c
blob29e24b1eee7ed0f0d9869ed8e524ff80c6666329
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 #if defined(__NetBSD__)
23 # if (NetBSD >= 199905) && !defined(IPFILTER_LKM) && defined(_KERNEL)
24 # include "opt_ipfilter.h"
25 # endif
26 #endif
27 #include <sys/file.h>
28 #if !defined(_KERNEL) && !defined(__KERNEL__)
29 # include <stdio.h>
30 # include <stdlib.h>
31 # include <string.h>
32 # define _KERNEL
33 # ifdef __OpenBSD__
34 struct file;
35 # endif
36 # include <sys/uio.h>
37 # undef _KERNEL
38 #else
39 # include <sys/systm.h>
40 # if defined(NetBSD) && (__NetBSD_Version__ >= 104000000)
41 # include <sys/proc.h>
42 # endif
43 #endif
44 #include <sys/time.h>
45 #if defined(_KERNEL) && !defined(SOLARIS2)
46 # include <sys/mbuf.h>
47 #endif
48 #if defined(__SVR4) || defined(__svr4__)
49 # include <sys/byteorder.h>
50 # ifdef _KERNEL
51 # include <sys/dditypes.h>
52 # endif
53 # include <sys/stream.h>
54 # include <sys/kmem.h>
55 #endif
56 #if defined(__FreeBSD_version) && (__FreeBSD_version >= 300000)
57 # include <sys/malloc.h>
58 #endif
60 #if defined(SOLARIS2) && !defined(_KERNEL)
61 # include "radix_ipf.h"
62 #endif
63 #if defined(_KERNEL) && (defined(__osf__) || defined(AIX) || \
64 defined(__hpux) || defined(__sgi))
65 # include "radix_ipf_local.h"
66 # define _RADIX_H_
67 #endif
68 #include <sys/socket.h>
69 #include <net/if.h>
70 #include <netinet/in.h>
72 #include "netinet/ip_compat.h"
73 #include "netinet/ip_fil.h"
74 #include "netinet/ip_pool.h"
76 #if defined(IPFILTER_LOOKUP) && defined(_KERNEL) && \
77 ((BSD >= 198911) && !defined(__osf__) && \
78 !defined(__hpux) && !defined(__sgi))
79 static int rn_freenode __P((struct radix_node *, void *));
80 #endif
82 /* END OF INCLUDES */
84 #if !defined(lint)
85 #if defined(__NetBSD__)
86 #include <sys/cdefs.h>
87 __KERNEL_RCSID(0, "$NetBSD$");
88 #else
89 static const char sccsid[] = "@(#)ip_fil.c 2.41 6/5/96 (C) 1993-2000 Darren Reed";
90 static const char rcsid[] = "@(#)Id: ip_pool.c,v 2.55.2.31 2009/07/18 19:05:39 darrenr Exp";
91 #endif
92 #endif
94 #ifdef IPFILTER_LOOKUP
96 # if !defined(RADIX_NODE_HEAD_LOCK) || !defined(RADIX_NODE_HEAD_UNLOCK) || \
97 !defined(_KERNEL)
98 # undef RADIX_NODE_HEAD_LOCK
99 # undef RADIX_NODE_HEAD_UNLOCK
100 # define RADIX_NODE_HEAD_LOCK(x) ;
101 # define RADIX_NODE_HEAD_UNLOCK(x) ;
102 # endif
104 static void ip_pool_clearnodes __P((ip_pool_t *));
105 static void *ip_pool_exists __P((int, char *));
107 ip_pool_stat_t ipoolstat;
108 ipfrwlock_t ip_poolrw;
110 ip_pool_t *ip_pool_list[IPL_LOGSIZE] = { NULL, NULL, NULL, NULL,
111 NULL, NULL, NULL, NULL };
114 #ifdef TEST_POOL
115 void treeprint __P((ip_pool_t *));
118 main(argc, argv)
119 int argc;
120 char *argv[];
122 addrfamily_t a, b;
123 iplookupop_t op;
124 ip_pool_t *ipo;
125 i6addr_t ip;
127 RWLOCK_INIT(&ip_poolrw, "poolrw");
128 ip_pool_init();
130 bzero((char *)&a, sizeof(a));
131 bzero((char *)&b, sizeof(b));
132 bzero((char *)&ip, sizeof(ip));
133 bzero((char *)&op, sizeof(op));
134 strlcpy(op.iplo_name, "0", sizeof(op.iplo_name));
136 if (ip_pool_create(&op) == 0)
137 ipo = ip_pool_exists(0, "0");
139 a.adf_addr.in4.s_addr = 0x0a010203;
140 b.adf_addr.in4.s_addr = 0xffffffff;
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 = 0x0a000000;
145 b.adf_addr.in4.s_addr = 0xff000000;
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 = 0x0a010100;
150 b.adf_addr.in4.s_addr = 0xffffff00;
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 = 0x0a010200;
155 b.adf_addr.in4.s_addr = 0xffffff00;
156 ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 0);
157 ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 0);
159 a.adf_addr.in4.s_addr = 0x0a010000;
160 b.adf_addr.in4.s_addr = 0xffff0000;
161 ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 1);
162 ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 1);
164 a.adf_addr.in4.s_addr = 0x0a01020f;
165 b.adf_addr.in4.s_addr = 0xffffffff;
166 ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 1);
167 ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 1);
168 #ifdef DEBUG_POOL
169 treeprint(ipo);
170 #endif
171 ip.in4.s_addr = 0x0a00aabb;
172 printf("search(%#x) = %d (0)\n", ip.in4.s_addr,
173 ip_pool_search(ipo, 4, &ip));
175 ip.in4.s_addr = 0x0a000001;
176 printf("search(%#x) = %d (0)\n", ip.in4.s_addr,
177 ip_pool_search(ipo, 4, &ip));
179 ip.in4.s_addr = 0x0a000101;
180 printf("search(%#x) = %d (0)\n", ip.in4.s_addr,
181 ip_pool_search(ipo, 4, &ip));
183 ip.in4.s_addr = 0x0a010001;
184 printf("search(%#x) = %d (1)\n", ip.in4.s_addr,
185 ip_pool_search(ipo, 4, &ip));
187 ip.in4.s_addr = 0x0a010101;
188 printf("search(%#x) = %d (1)\n", ip.in4.s_addr,
189 ip_pool_search(ipo, 4, &ip));
191 ip.in4.s_addr = 0x0a010201;
192 printf("search(%#x) = %d (0)\n", ip.in4.s_addr,
193 ip_pool_search(ipo, 4, &ip));
195 ip.in4.s_addr = 0x0a010203;
196 printf("search(%#x) = %d (1)\n", ip.in4.s_addr,
197 ip_pool_search(ipo, 4, &ip));
199 ip.in4.s_addr = 0x0a01020f;
200 printf("search(%#x) = %d (1)\n", ip.in4.s_addr,
201 ip_pool_search(ipo, 4, &ip));
203 ip.in4.s_addr = 0x0b00aabb;
204 printf("search(%#x) = %d (-1)\n", ip.in4.s_addr,
205 ip_pool_search(ipo, 4, &ip));
207 #ifdef DEBUG_POOL
208 treeprint(ipo);
209 #endif
211 ip_pool_fini();
213 return 0;
217 void
218 treeprint(ipo)
219 ip_pool_t *ipo;
221 ip_pool_node_t *c;
223 for (c = ipo->ipo_list; c != NULL; c = c->ipn_next)
224 printf("Node %p(%s) (%#x/%#x) = %d hits %lu\n",
225 c, c->ipn_name, c->ipn_addr.adf_addr.in4.s_addr,
226 c->ipn_mask.adf_addr.in4.s_addr,
227 c->ipn_info, c->ipn_hits);
229 #endif /* TEST_POOL */
232 /* ------------------------------------------------------------------------ */
233 /* Function: ip_pool_init */
234 /* Returns: int - 0 = success, else error */
235 /* */
236 /* Initialise the routing table data structures where required. */
237 /* ------------------------------------------------------------------------ */
238 int ip_pool_init()
241 bzero((char *)&ipoolstat, sizeof(ipoolstat));
243 #if (!defined(_KERNEL) || !defined(BSD) || (BSD < 199306))
244 rn_init();
245 #endif
246 return 0;
250 /* ------------------------------------------------------------------------ */
251 /* Function: ip_pool_fini */
252 /* Returns: int - 0 = success, else error */
253 /* Locks: WRITE(ipf_global) */
254 /* */
255 /* Clean up all the pool data structures allocated and call the cleanup */
256 /* function for the radix tree that supports the pools. ip_pool_destroy() is*/
257 /* used to delete the pools one by one to ensure they're properly freed up. */
258 /* ------------------------------------------------------------------------ */
259 void ip_pool_fini()
261 ip_pool_t *p, *q;
262 int i;
264 for (i = 0; i <= IPL_LOGMAX; i++) {
265 for (q = ip_pool_list[i]; (p = q) != NULL; ) {
266 q = p->ipo_next;
267 (void) ip_pool_destroy(i, p->ipo_name);
271 #if (!defined(_KERNEL) || !defined(BSD) || (BSD < 199306))
272 rn_fini();
273 #endif
277 /* ------------------------------------------------------------------------ */
278 /* Function: ip_pool_statistics */
279 /* Returns: int - 0 = success, else error */
280 /* Parameters: op(I) - pointer to lookup operation arguments */
281 /* */
282 /* Copy the current statistics out into user space, collecting pool list */
283 /* pointers as appropriate for later use. */
284 /* ------------------------------------------------------------------------ */
285 int ip_pool_statistics(op)
286 iplookupop_t *op;
288 ip_pool_stat_t stats;
289 int unit, i, err = 0;
291 if (op->iplo_size != sizeof(ipoolstat))
292 return EINVAL;
294 bcopy((char *)&ipoolstat, (char *)&stats, sizeof(stats));
295 unit = op->iplo_unit;
296 if (unit == IPL_LOGALL) {
297 for (i = 0; i < IPL_LOGSIZE; i++)
298 stats.ipls_list[i] = ip_pool_list[i];
299 } else if (unit >= 0 && unit < IPL_LOGSIZE) {
300 if (op->iplo_name[0] != '\0')
301 stats.ipls_list[unit] = ip_pool_exists(unit,
302 op->iplo_name);
303 else
304 stats.ipls_list[unit] = ip_pool_list[unit];
305 } else
306 err = EINVAL;
307 if (err == 0)
308 err = COPYOUT(&stats, op->iplo_struct, sizeof(stats));
309 return err;
313 /* ------------------------------------------------------------------------ */
314 /* Function: ip_pool_exists */
315 /* Returns: int - 0 = success, else error */
316 /* Parameters: ipo(I) - pointer to the pool getting the new node. */
317 /* */
318 /* Find a matching pool inside the collection of pools for a particular */
319 /* device, indicated by the unit number. */
320 /* ------------------------------------------------------------------------ */
321 static void *ip_pool_exists(unit, name)
322 int unit;
323 char *name;
325 ip_pool_t *p;
327 for (p = ip_pool_list[unit]; p != NULL; p = p->ipo_next)
328 if (strncmp(p->ipo_name, name, sizeof(p->ipo_name)) == 0)
329 break;
330 return p;
334 /* ------------------------------------------------------------------------ */
335 /* Function: ip_pool_find */
336 /* Returns: int - 0 = success, else error */
337 /* Parameters: ipo(I) - pointer to the pool getting the new node. */
338 /* */
339 /* Find a matching pool inside the collection of pools for a particular */
340 /* device, indicated by the unit number. If it is marked for deletion then */
341 /* pretend it does not exist. */
342 /* ------------------------------------------------------------------------ */
343 void *ip_pool_find(unit, name)
344 int unit;
345 char *name;
347 ip_pool_t *p;
349 p = ip_pool_exists(unit, name);
350 if ((p != NULL) && (p->ipo_flags & IPOOL_DELETE))
351 return NULL;
353 return p;
357 /* ------------------------------------------------------------------------ */
358 /* Function: ip_pool_findeq */
359 /* Returns: int - 0 = success, else error */
360 /* Parameters: ipo(I) - pointer to the pool getting the new node. */
361 /* addr(I) - pointer to address information to delete */
362 /* mask(I) - */
363 /* */
364 /* Searches for an exact match of an entry in the pool. */
365 /* ------------------------------------------------------------------------ */
366 ip_pool_node_t *ip_pool_findeq(ipo, addr, mask)
367 ip_pool_t *ipo;
368 addrfamily_t *addr, *mask;
370 struct radix_node *n;
371 SPL_INT(s);
373 SPL_NET(s);
374 RADIX_NODE_HEAD_LOCK(ipo->ipo_head);
375 n = ipo->ipo_head->rnh_lookup(addr, mask, ipo->ipo_head);
376 RADIX_NODE_HEAD_UNLOCK(ipo->ipo_head);
377 SPL_X(s);
378 return (ip_pool_node_t *)n;
382 /* ------------------------------------------------------------------------ */
383 /* Function: ip_pool_search */
384 /* Returns: int - 0 == +ve match, -1 == error, 1 == -ve/no match */
385 /* Parameters: tptr(I) - pointer to the pool to search */
386 /* ipversion(I) - IP protocol version (4 or 6) */
387 /* dptr(I) - pointer to address information */
388 /* */
389 /* Search the pool for a given address and return a search result. */
390 /* ------------------------------------------------------------------------ */
391 int ip_pool_search(tptr, ipversion, dptr)
392 void *tptr;
393 int ipversion;
394 void *dptr;
396 struct radix_node *rn;
397 ip_pool_node_t *m;
398 i6addr_t *addr;
399 addrfamily_t v;
400 ip_pool_t *ipo;
401 int rv;
403 ipo = tptr;
404 if (ipo == NULL)
405 return -1;
407 rv = 1;
408 m = NULL;
409 addr = (i6addr_t *)dptr;
410 bzero(&v, sizeof(v));
411 v.adf_len = offsetof(addrfamily_t, adf_addr);
413 if (ipversion == 4) {
414 v.adf_len += sizeof(addr->in4);
415 v.adf_addr.in4 = addr->in4;
416 #ifdef USE_INET6
417 } else if (ipversion == 6) {
418 v.adf_len += sizeof(addr->in6);
419 v.adf_addr.in6 = addr->in6;
420 #endif
421 } else
422 return -1;
424 READ_ENTER(&ip_poolrw);
426 RADIX_NODE_HEAD_LOCK(ipo->ipo_head);
427 rn = ipo->ipo_head->rnh_matchaddr(&v, ipo->ipo_head);
428 RADIX_NODE_HEAD_UNLOCK(ipo->ipo_head);
430 if ((rn != NULL) && ((rn->rn_flags & RNF_ROOT) == 0)) {
431 m = (ip_pool_node_t *)rn;
432 ipo->ipo_hits++;
433 m->ipn_hits++;
434 rv = m->ipn_info;
436 RWLOCK_EXIT(&ip_poolrw);
437 return rv;
441 /* ------------------------------------------------------------------------ */
442 /* Function: ip_pool_insert */
443 /* Returns: int - 0 = success, else error */
444 /* Parameters: ipo(I) - pointer to the pool getting the new node. */
445 /* addr(I) - address being added as a node */
446 /* mask(I) - netmask to with the node being added */
447 /* info(I) - extra information to store in this node. */
448 /* Locks: WRITE(ip_poolrw) */
449 /* */
450 /* Add another node to the pool given by ipo. The three parameters passed */
451 /* in (addr, mask, info) shold all be stored in the node. */
452 /* ------------------------------------------------------------------------ */
453 int ip_pool_insert(ipo, addr, mask, info)
454 ip_pool_t *ipo;
455 i6addr_t *addr, *mask;
456 int info;
458 struct radix_node *rn;
459 ip_pool_node_t *x;
461 KMALLOC(x, ip_pool_node_t *);
462 if (x == NULL) {
463 return ENOMEM;
466 bzero(x, sizeof(*x));
468 x->ipn_info = info;
469 (void)strncpy(x->ipn_name, ipo->ipo_name, sizeof(x->ipn_name));
471 bcopy(addr, &x->ipn_addr.adf_addr, sizeof(*addr));
472 x->ipn_addr.adf_len = sizeof(x->ipn_addr);
473 bcopy(mask, &x->ipn_mask.adf_addr, sizeof(*mask));
474 x->ipn_mask.adf_len = sizeof(x->ipn_mask);
476 RADIX_NODE_HEAD_LOCK(ipo->ipo_head);
477 rn = ipo->ipo_head->rnh_addaddr(&x->ipn_addr, &x->ipn_mask,
478 ipo->ipo_head, x->ipn_nodes);
479 RADIX_NODE_HEAD_UNLOCK(ipo->ipo_head);
480 #ifdef DEBUG_POOL
481 printf("Added %p at %p\n", x, rn);
482 #endif
484 if (rn == NULL) {
485 KFREE(x);
486 return ENOMEM;
489 x->ipn_ref = 1;
490 x->ipn_next = ipo->ipo_list;
491 x->ipn_pnext = &ipo->ipo_list;
492 if (ipo->ipo_list != NULL)
493 ipo->ipo_list->ipn_pnext = &x->ipn_next;
494 ipo->ipo_list = x;
496 ipoolstat.ipls_nodes++;
498 return 0;
502 /* ------------------------------------------------------------------------ */
503 /* Function: ip_pool_create */
504 /* Returns: int - 0 = success, else error */
505 /* Parameters: op(I) - pointer to iplookup struct with call details */
506 /* Locks: WRITE(ip_poolrw) */
507 /* */
508 /* Creates a new group according to the paramters passed in via the */
509 /* iplookupop structure. Does not check to see if the group already exists */
510 /* when being inserted - assume this has already been done. If the pool is */
511 /* marked as being anonymous, give it a new, unique, identifier. Call any */
512 /* other functions required to initialise the structure. */
513 /* */
514 /* If the structure is flagged for deletion then reset the flag and return, */
515 /* as this likely means we've tried to free a pool that is in use (flush) */
516 /* and now want to repopulate it with "new" data. */
517 /* ------------------------------------------------------------------------ */
518 int ip_pool_create(op)
519 iplookupop_t *op;
521 char name[FR_GROUPLEN];
522 int poolnum, unit;
523 ip_pool_t *h;
525 unit = op->iplo_unit;
527 if ((op->iplo_arg & LOOKUP_ANON) == 0) {
528 h = ip_pool_exists(unit, op->iplo_name);
529 if (h != NULL) {
530 if ((h->ipo_flags & IPOOL_DELETE) == 0)
531 return EEXIST;
532 h->ipo_flags &= ~IPOOL_DELETE;
533 return 0;
537 KMALLOC(h, ip_pool_t *);
538 if (h == NULL)
539 return ENOMEM;
540 bzero(h, sizeof(*h));
542 if (rn_inithead((void **)&h->ipo_head,
543 offsetof(addrfamily_t, adf_addr) << 3) == 0) {
544 KFREE(h);
545 return ENOMEM;
548 if ((op->iplo_arg & LOOKUP_ANON) != 0) {
549 ip_pool_t *p;
551 h->ipo_flags |= IPOOL_ANON;
552 poolnum = LOOKUP_ANON;
554 #if defined(SNPRINTF) && defined(_KERNEL)
555 SNPRINTF(name, sizeof(name), "%x", poolnum);
556 #else
557 (void)sprintf(name, "%x", poolnum);
558 #endif
560 for (p = ip_pool_list[unit]; p != NULL; ) {
561 if (strncmp(name, p->ipo_name,
562 sizeof(p->ipo_name)) == 0) {
563 poolnum++;
564 #if defined(SNPRINTF) && defined(_KERNEL)
565 SNPRINTF(name, sizeof(name), "%x", poolnum);
566 #else
567 (void)sprintf(name, "%x", poolnum);
568 #endif
569 p = ip_pool_list[unit];
570 } else
571 p = p->ipo_next;
574 (void)strncpy(h->ipo_name, name, sizeof(h->ipo_name));
575 (void)strncpy(op->iplo_name, name, sizeof(op->iplo_name));
576 } else {
577 (void)strncpy(h->ipo_name, op->iplo_name, sizeof(h->ipo_name));
580 h->ipo_ref = 1;
581 h->ipo_list = NULL;
582 h->ipo_unit = unit;
583 h->ipo_next = ip_pool_list[unit];
584 if (ip_pool_list[unit] != NULL)
585 ip_pool_list[unit]->ipo_pnext = &h->ipo_next;
586 h->ipo_pnext = &ip_pool_list[unit];
587 ip_pool_list[unit] = h;
589 ipoolstat.ipls_pools++;
591 return 0;
595 /* ------------------------------------------------------------------------ */
596 /* Function: ip_pool_remove */
597 /* Returns: int - 0 = success, else error */
598 /* Parameters: ipo(I) - pointer to the pool to remove the node from. */
599 /* ipe(I) - address being deleted as a node */
600 /* Locks: WRITE(ip_poolrw) */
601 /* */
602 /* Remove a node from the pool given by ipo. */
603 /* ------------------------------------------------------------------------ */
604 int ip_pool_remove(ipo, ipe)
605 ip_pool_t *ipo;
606 ip_pool_node_t *ipe;
609 if (ipe->ipn_pnext != NULL)
610 *ipe->ipn_pnext = ipe->ipn_next;
611 if (ipe->ipn_next != NULL)
612 ipe->ipn_next->ipn_pnext = ipe->ipn_pnext;
614 RADIX_NODE_HEAD_LOCK(ipo->ipo_head);
615 ipo->ipo_head->rnh_deladdr(&ipe->ipn_addr, &ipe->ipn_mask,
616 ipo->ipo_head);
617 RADIX_NODE_HEAD_UNLOCK(ipo->ipo_head);
619 ip_pool_node_deref(ipe);
621 return 0;
625 /* ------------------------------------------------------------------------ */
626 /* Function: ip_pool_destroy */
627 /* Returns: int - 0 = success, else error */
628 /* Parameters: op(I) - information about the pool to remove */
629 /* Locks: WRITE(ip_poolrw) or WRITE(ipf_global) */
630 /* */
631 /* Search for a pool using paramters passed in and if it's not otherwise */
632 /* busy, free it. If it is busy, clear all of its nodes, mark it for being */
633 /* deleted and return an error saying it is busy. */
634 /* */
635 /* NOTE: Because this function is called out of ipfdetach() where ip_poolrw */
636 /* may not be initialised, we can't use an ASSERT to enforce the locking */
637 /* assertion that one of the two (ip_poolrw,ipf_global) is held. */
638 /* ------------------------------------------------------------------------ */
639 int ip_pool_destroy(unit, name)
640 int unit;
641 char *name;
643 ip_pool_t *ipo;
645 ipo = ip_pool_exists(unit, name);
646 if (ipo == NULL)
647 return ESRCH;
649 if (ipo->ipo_ref != 1) {
650 ip_pool_clearnodes(ipo);
651 ipo->ipo_flags |= IPOOL_DELETE;
652 return 0;
655 ip_pool_free(ipo);
656 return 0;
660 /* ------------------------------------------------------------------------ */
661 /* Function: ip_pool_flush */
662 /* Returns: int - number of pools deleted */
663 /* Parameters: fp(I) - which pool(s) to flush */
664 /* Locks: WRITE(ip_poolrw) or WRITE(ipf_global) */
665 /* */
666 /* Free all pools associated with the device that matches the unit number */
667 /* passed in with operation. */
668 /* */
669 /* NOTE: Because this function is called out of ipfdetach() where ip_poolrw */
670 /* may not be initialised, we can't use an ASSERT to enforce the locking */
671 /* assertion that one of the two (ip_poolrw,ipf_global) is held. */
672 /* ------------------------------------------------------------------------ */
673 int ip_pool_flush(fp)
674 iplookupflush_t *fp;
676 int i, num = 0, unit, err;
677 ip_pool_t *p, *q;
678 iplookupop_t op;
680 unit = fp->iplf_unit;
682 for (i = 0; i <= IPL_LOGMAX; i++) {
683 if (unit != IPLT_ALL && i != unit)
684 continue;
685 for (q = ip_pool_list[i]; (p = q) != NULL; ) {
686 op.iplo_unit = i;
687 (void)strncpy(op.iplo_name, p->ipo_name,
688 sizeof(op.iplo_name));
689 q = p->ipo_next;
690 err = ip_pool_destroy(op.iplo_unit, op.iplo_name);
691 if (err == 0)
692 num++;
693 else
694 break;
697 return num;
701 /* ------------------------------------------------------------------------ */
702 /* Function: ip_pool_free */
703 /* Returns: void */
704 /* Parameters: ipo(I) - pointer to pool structure */
705 /* Locks: WRITE(ip_poolrw) or WRITE(ipf_global) */
706 /* */
707 /* Deletes the pool strucutre passed in from the list of pools and deletes */
708 /* all of the address information stored in it, including any tree data */
709 /* structures also allocated. */
710 /* */
711 /* NOTE: Because this function is called out of ipfdetach() where ip_poolrw */
712 /* may not be initialised, we can't use an ASSERT to enforce the locking */
713 /* assertion that one of the two (ip_poolrw,ipf_global) is held. */
714 /* ------------------------------------------------------------------------ */
715 void ip_pool_free(ipo)
716 ip_pool_t *ipo;
719 ip_pool_clearnodes(ipo);
721 if (ipo->ipo_next != NULL)
722 ipo->ipo_next->ipo_pnext = ipo->ipo_pnext;
723 *ipo->ipo_pnext = ipo->ipo_next;
724 rn_freehead(ipo->ipo_head);
725 KFREE(ipo);
727 ipoolstat.ipls_pools--;
731 /* ------------------------------------------------------------------------ */
732 /* Function: ip_pool_clearnodes */
733 /* Returns: void */
734 /* Parameters: ipo(I) - pointer to pool structure */
735 /* Locks: WRITE(ip_poolrw) or WRITE(ipf_global) */
736 /* */
737 /* Deletes all nodes stored in a pool structure. */
738 /* ------------------------------------------------------------------------ */
739 static void ip_pool_clearnodes(ipo)
740 ip_pool_t *ipo;
742 ip_pool_node_t *n;
744 RADIX_NODE_HEAD_LOCK(ipo->ipo_head);
745 while ((n = ipo->ipo_list) != NULL) {
746 ipo->ipo_head->rnh_deladdr(&n->ipn_addr, &n->ipn_mask,
747 ipo->ipo_head);
749 *n->ipn_pnext = n->ipn_next;
750 if (n->ipn_next)
751 n->ipn_next->ipn_pnext = n->ipn_pnext;
753 KFREE(n);
755 ipoolstat.ipls_nodes--;
757 RADIX_NODE_HEAD_UNLOCK(ipo->ipo_head);
759 ipo->ipo_list = NULL;
763 /* ------------------------------------------------------------------------ */
764 /* Function: ip_pool_deref */
765 /* Returns: void */
766 /* Parameters: ipo(I) - pointer to pool structure */
767 /* Locks: WRITE(ip_poolrw) */
768 /* */
769 /* Drop the number of known references to this pool structure by one and if */
770 /* we arrive at zero known references, free it. */
771 /* ------------------------------------------------------------------------ */
772 void ip_pool_deref(ipo)
773 ip_pool_t *ipo;
776 ipo->ipo_ref--;
778 if (ipo->ipo_ref == 0)
779 ip_pool_free(ipo);
781 else if ((ipo->ipo_ref == 1) && (ipo->ipo_flags & IPOOL_DELETE))
782 ip_pool_destroy(ipo->ipo_unit, ipo->ipo_name);
786 /* ------------------------------------------------------------------------ */
787 /* Function: ip_pool_node_deref */
788 /* Returns: void */
789 /* Parameters: ipn(I) - pointer to pool structure */
790 /* Locks: WRITE(ip_poolrw) */
791 /* */
792 /* Drop a reference to the pool node passed in and if we're the last, free */
793 /* it all up and adjust the stats accordingly. */
794 /* ------------------------------------------------------------------------ */
795 void ip_pool_node_deref(ipn)
796 ip_pool_node_t *ipn;
799 ipn->ipn_ref--;
801 if (ipn->ipn_ref == 0) {
802 KFREE(ipn);
803 ipoolstat.ipls_nodes--;
808 /* ------------------------------------------------------------------------ */
809 /* Function: ip_pool_getnext */
810 /* Returns: void */
811 /* Parameters: token(I) - pointer to pool structure */
812 /* ilp(IO) - pointer to pool iterating structure */
813 /* */
814 /* ------------------------------------------------------------------------ */
815 int ip_pool_getnext(token, ilp)
816 ipftoken_t *token;
817 ipflookupiter_t *ilp;
819 ip_pool_node_t *node, zn, *nextnode;
820 ip_pool_t *ipo, zp, *nextipo;
821 int err;
823 err = 0;
824 node = NULL;
825 nextnode = NULL;
826 ipo = NULL;
827 nextipo = NULL;
829 READ_ENTER(&ip_poolrw);
832 * Get "previous" entry from token. Find next entry to process,
833 * and add reference to it and update the token.
835 switch (ilp->ili_otype)
837 case IPFLOOKUPITER_LIST :
838 ipo = token->ipt_data;
839 if (ipo == NULL) {
840 nextipo = ip_pool_list[(int)ilp->ili_unit];
841 } else {
842 nextipo = ipo->ipo_next;
845 if (nextipo != NULL) {
846 ATOMIC_INC(nextipo->ipo_ref);
847 token->ipt_data = nextipo;
848 } else {
849 bzero((char *)&zp, sizeof(zp));
850 nextipo = &zp;
851 token->ipt_data = NULL;
853 break;
855 case IPFLOOKUPITER_NODE :
856 node = token->ipt_data;
857 if (node == NULL) {
858 ipo = ip_pool_exists(ilp->ili_unit, ilp->ili_name);
859 if (ipo == NULL)
860 err = ESRCH;
861 else {
862 nextnode = ipo->ipo_list;
863 ipo = NULL;
865 } else {
866 nextnode = node->ipn_next;
869 if (nextnode != NULL) {
870 ATOMIC_INC(nextnode->ipn_ref);
871 token->ipt_data = nextnode;
872 } else {
873 bzero((char *)&zn, sizeof(zn));
874 nextnode = &zn;
875 token->ipt_data = NULL;
877 break;
879 default :
880 err = EINVAL;
881 break;
885 * Now that we have ref, it's save to give up lock.
887 RWLOCK_EXIT(&ip_poolrw);
889 if (err != 0)
890 return err;
893 * Copy out the data and update the references and token as needed.
895 switch (ilp->ili_otype)
897 case IPFLOOKUPITER_LIST :
898 err = COPYOUT(nextipo, ilp->ili_data, sizeof(*nextipo));
899 if (err != 0)
900 err = EFAULT;
901 if (token->ipt_data != NULL) {
902 if (ipo != NULL) {
903 WRITE_ENTER(&ip_poolrw);
904 ip_pool_deref(ipo);
905 RWLOCK_EXIT(&ip_poolrw);
907 if (nextipo->ipo_next == NULL)
908 token->ipt_data = NULL;
910 break;
912 case IPFLOOKUPITER_NODE :
913 err = COPYOUT(nextnode, ilp->ili_data, sizeof(*nextnode));
914 if (err != 0)
915 err = EFAULT;
916 if (token->ipt_data != NULL) {
917 if (node != NULL) {
918 WRITE_ENTER(&ip_poolrw);
919 ip_pool_node_deref(node);
920 RWLOCK_EXIT(&ip_poolrw);
922 if (nextnode->ipn_next == NULL)
923 token->ipt_data = NULL;
925 break;
928 return err;
932 /* ------------------------------------------------------------------------ */
933 /* Function: ip_pool_iterderef */
934 /* Returns: void */
935 /* Parameters: ipn(I) - pointer to pool structure */
936 /* Locks: WRITE(ip_poolrw) */
937 /* */
938 /* ------------------------------------------------------------------------ */
939 void ip_pool_iterderef(otype, unit, data)
940 u_int otype;
941 int unit;
942 void *data;
945 if (data == NULL)
946 return;
948 if (unit < 0 || unit > IPL_LOGMAX)
949 return;
951 switch (otype)
953 case IPFLOOKUPITER_LIST :
954 WRITE_ENTER(&ip_poolrw);
955 ip_pool_deref((ip_pool_t *)data);
956 RWLOCK_EXIT(&ip_poolrw);
957 break;
959 case IPFLOOKUPITER_NODE :
960 WRITE_ENTER(&ip_poolrw);
961 ip_pool_node_deref((ip_pool_node_t *)data);
962 RWLOCK_EXIT(&ip_poolrw);
963 break;
964 default :
965 break;
970 # if defined(_KERNEL) && (defined(BSD) && (BSD >= 198911) && \
971 !defined(__osf__) && !defined(__hpux) && !defined(__sgi))
972 static int
973 rn_freenode(struct radix_node *n, void *p)
975 struct radix_node_head *rnh = p;
976 struct radix_node *d;
978 d = rnh->rnh_deladdr(n->rn_key, NULL, rnh);
979 if (d != NULL) {
980 FreeS(d, max_keylen + 2 * sizeof (*d));
982 return 0;
986 void
987 rn_freehead(rnh)
988 struct radix_node_head *rnh;
991 RADIX_NODE_HEAD_LOCK(rnh);
992 # if defined(__NetBSD_Version__) && (__NetBSD_Version__ > 499002000)
993 rn_walktree(rnh, rn_freenode, rnh);
994 # else
995 (*rnh->rnh_walktree)(rnh, rn_freenode, rnh);
996 # endif
998 rnh->rnh_addaddr = NULL;
999 rnh->rnh_deladdr = NULL;
1000 rnh->rnh_matchaddr = NULL;
1001 rnh->rnh_lookup = NULL;
1002 RADIX_NODE_HEAD_UNLOCK(rnh);
1004 Free(rnh);
1006 # endif
1007 #endif /* IPFILTER_LOOKUP */