2 * Copyright (C) 2012 by Darren Reed.
4 * See the IPFILTER.LICENCE file for details on licencing.
6 #if defined(KERNEL) || defined(_KERNEL)
12 #include <sys/errno.h>
13 #include <sys/types.h>
14 #include <sys/param.h>
16 #if !defined(_KERNEL) && !defined(__KERNEL__)
24 # include <sys/systm.h>
25 # if defined(NetBSD) && (__NetBSD_Version__ >= 104000000)
26 # include <sys/proc.h>
30 #if defined(_KERNEL) && !defined(SOLARIS2)
31 # include <sys/mbuf.h>
34 # include <sys/byteorder.h>
36 # include <sys/dditypes.h>
38 # include <sys/stream.h>
39 # include <sys/kmem.h>
41 #if defined(__FreeBSD__)
42 # include <sys/malloc.h>
45 #include <sys/socket.h>
47 #include <netinet/in.h>
52 #include "netinet/ip_compat.h"
53 #include "netinet/ip_fil.h"
54 #include "netinet/ip_pool.h"
55 #include "netinet/radix_ipf.h"
60 static const char sccsid[] = "@(#)ip_fil.c 2.41 6/5/96 (C) 1993-2000 Darren Reed";
61 static const char rcsid[] = "@(#)$Id$";
64 typedef struct ipf_pool_softc_s {
66 ip_pool_t *ipf_pool_list[LOOKUP_POOL_SZ];
67 ipf_pool_stat_t ipf_pool_stats;
68 ip_pool_node_t *ipf_node_explist;
72 static void ipf_pool_clearnodes(ipf_main_softc_t *, ipf_pool_softc_t *,
74 static int ipf_pool_create(ipf_main_softc_t *, ipf_pool_softc_t *, iplookupop_t *);
75 static int ipf_pool_deref(ipf_main_softc_t *, void *, void *);
76 static int ipf_pool_destroy(ipf_main_softc_t *, ipf_pool_softc_t *, int, char *);
77 static void *ipf_pool_exists(ipf_pool_softc_t *, int, char *);
78 static void *ipf_pool_find(void *, int, char *);
79 static ip_pool_node_t *ipf_pool_findeq(ipf_pool_softc_t *, ip_pool_t *,
80 addrfamily_t *, addrfamily_t *);
81 static void ipf_pool_free(ipf_main_softc_t *, ipf_pool_softc_t *,
83 static int ipf_pool_insert_node(ipf_main_softc_t *, ipf_pool_softc_t *,
84 ip_pool_t *, struct ip_pool_node *);
85 static int ipf_pool_iter_deref(ipf_main_softc_t *, void *, int, int, void *);
86 static int ipf_pool_iter_next(ipf_main_softc_t *, void *, ipftoken_t *,
88 static size_t ipf_pool_flush(ipf_main_softc_t *, void *, iplookupflush_t *);
89 static int ipf_pool_node_add(ipf_main_softc_t *, void *, iplookupop_t *,
91 static int ipf_pool_node_del(ipf_main_softc_t *, void *, iplookupop_t *,
93 static void ipf_pool_node_deref(ipf_pool_softc_t *, ip_pool_node_t *);
94 static int ipf_pool_remove_node(ipf_main_softc_t *, ipf_pool_softc_t *,
95 ip_pool_t *, ip_pool_node_t *);
96 static int ipf_pool_search(ipf_main_softc_t *, void *, int,
98 static void *ipf_pool_soft_create(ipf_main_softc_t *);
99 static void ipf_pool_soft_destroy(ipf_main_softc_t *, void *);
100 static void ipf_pool_soft_fini(ipf_main_softc_t *, void *);
101 static int ipf_pool_soft_init(ipf_main_softc_t *, void *);
102 static int ipf_pool_stats_get(ipf_main_softc_t *, void *, iplookupop_t *);
103 static int ipf_pool_table_add(ipf_main_softc_t *, void *, iplookupop_t *);
104 static int ipf_pool_table_del(ipf_main_softc_t *, void *, iplookupop_t *);
105 static void *ipf_pool_select_add_ref(void *, int, char *);
106 static void ipf_pool_expire(ipf_main_softc_t *, void *);
108 ipf_lookup_t ipf_pool_backend = {
110 ipf_pool_soft_create,
111 ipf_pool_soft_destroy,
125 ipf_pool_select_add_ref,
133 void treeprint(ip_pool_t *);
146 RWLOCK_INIT(softc->ipf_poolrw, "poolrw");
149 bzero((char *)&ip, sizeof(ip));
150 bzero((char *)&op, sizeof(op));
151 bzero((char *)&node, sizeof(node));
152 strcpy(op.iplo_name, "0");
154 if (ipf_pool_create(&op) == 0)
155 ipo = ipf_pool_exists(0, "0");
157 node.ipn_addr.adf_family = AF_INET;
159 node.ipn_addr.adf_addr.in4.s_addr = 0x0a010203;
160 node.ipn_mask.adf_addr.in4.s_addr = 0xffffffff;
162 ipf_pool_insert_node(ipo, &node);
164 node.ipn_addr.adf_addr.in4.s_addr = 0x0a000000;
165 node.ipn_mask.adf_addr.in4.s_addr = 0xff000000;
167 ipf_pool_insert_node(ipo, &node);
169 node.ipn_addr.adf_addr.in4.s_addr = 0x0a010100;
170 node.ipn_mask.adf_addr.in4.s_addr = 0xffffff00;
172 ipf_pool_insert_node(ipo, &node);
174 node.ipn_addr.adf_addr.in4.s_addr = 0x0a010200;
175 node.ipn_mask.adf_addr.in4.s_addr = 0xffffff00;
177 ipf_pool_insert_node(ipo, &node);
179 node.ipn_addr.adf_addr.in4.s_addr = 0x0a010000;
180 node.ipn_mask.adf_addr.in4.s_addr = 0xffff0000;
182 ipf_pool_insert_node(ipo, &node);
184 node.ipn_addr.adf_addr.in4.s_addr = 0x0a01020f;
185 node.ipn_mask.adf_addr.in4.s_addr = 0xffffffff;
187 ipf_pool_insert_node(ipo, &node);
191 ip.in4.s_addr = 0x0a00aabb;
192 printf("search(%#x) = %d (0)\n", ip.in4.s_addr,
193 ipf_pool_search(ipo, 4, &ip, 1));
195 ip.in4.s_addr = 0x0a000001;
196 printf("search(%#x) = %d (0)\n", ip.in4.s_addr,
197 ipf_pool_search(ipo, 4, &ip, 1));
199 ip.in4.s_addr = 0x0a000101;
200 printf("search(%#x) = %d (0)\n", ip.in4.s_addr,
201 ipf_pool_search(ipo, 4, &ip, 1));
203 ip.in4.s_addr = 0x0a010001;
204 printf("search(%#x) = %d (1)\n", ip.in4.s_addr,
205 ipf_pool_search(ipo, 4, &ip, 1));
207 ip.in4.s_addr = 0x0a010101;
208 printf("search(%#x) = %d (1)\n", ip.in4.s_addr,
209 ipf_pool_search(ipo, 4, &ip, 1));
211 ip.in4.s_addr = 0x0a010201;
212 printf("search(%#x) = %d (0)\n", ip.in4.s_addr,
213 ipf_pool_search(ipo, 4, &ip, 1));
215 ip.in4.s_addr = 0x0a010203;
216 printf("search(%#x) = %d (1)\n", ip.in4.s_addr,
217 ipf_pool_search(ipo, 4, &ip, 1));
219 ip.in4.s_addr = 0x0a01020f;
220 printf("search(%#x) = %d (1)\n", ip.in4.s_addr,
221 ipf_pool_search(ipo, 4, &ip, 1));
223 ip.in4.s_addr = 0x0b00aabb;
224 printf("search(%#x) = %d (-1)\n", ip.in4.s_addr,
225 ipf_pool_search(ipo, 4, &ip, 1));
243 for (c = ipo->ipo_list; c != NULL; c = c->ipn_next)
244 printf("Node %p(%s) (%#x/%#x) = %d hits %lu\n",
245 c, c->ipn_name, c->ipn_addr.adf_addr.in4.s_addr,
246 c->ipn_mask.adf_addr.in4.s_addr,
247 c->ipn_info, c->ipn_hits);
249 #endif /* TEST_POOL */
252 /* ------------------------------------------------------------------------ */
253 /* Function: ipf_pool_soft_create */
254 /* Returns: void * - NULL = failure, else pointer to local context */
255 /* Parameters: softc(I) - pointer to soft context main structure */
257 /* Initialise the routing table data structures where required. */
258 /* ------------------------------------------------------------------------ */
260 ipf_pool_soft_create(softc)
261 ipf_main_softc_t *softc;
263 ipf_pool_softc_t *softp;
265 KMALLOC(softp, ipf_pool_softc_t *);
271 bzero((char *)softp, sizeof(*softp));
273 softp->ipf_radix = ipf_rx_create();
274 if (softp->ipf_radix == NULL) {
284 /* ------------------------------------------------------------------------ */
285 /* Function: ipf_pool_soft_init */
286 /* Returns: int - 0 = success, else error */
287 /* Parameters: softc(I) - pointer to soft context main structure */
288 /* arg(I) - pointer to local context to use */
290 /* Initialise the routing table data structures where required. */
291 /* ------------------------------------------------------------------------ */
293 ipf_pool_soft_init(softc, arg)
294 ipf_main_softc_t *softc;
297 ipf_pool_softc_t *softp = arg;
299 ipf_rx_init(softp->ipf_radix);
305 /* ------------------------------------------------------------------------ */
306 /* Function: ipf_pool_soft_fini */
308 /* Parameters: softc(I) - pointer to soft context main structure */
309 /* arg(I) - pointer to local context to use */
310 /* Locks: WRITE(ipf_global) */
312 /* Clean up all the pool data structures allocated and call the cleanup */
313 /* function for the radix tree that supports the pools. ipf_pool_destroy is */
314 /* used to delete the pools one by one to ensure they're properly freed up. */
315 /* ------------------------------------------------------------------------ */
317 ipf_pool_soft_fini(softc, arg)
318 ipf_main_softc_t *softc;
321 ipf_pool_softc_t *softp = arg;
327 for (i = -1; i <= IPL_LOGMAX; i++) {
328 for (q = softp->ipf_pool_list[i + 1]; (p = q) != NULL; ) {
330 (void) ipf_pool_destroy(softc, arg, i, p->ipo_name);
336 /* ------------------------------------------------------------------------ */
337 /* Function: ipf_pool_soft_destroy */
339 /* Parameters: softc(I) - pointer to soft context main structure */
340 /* arg(I) - pointer to local context to use */
342 /* Clean up the pool by free'ing the radix tree associated with it and free */
343 /* up the pool context too. */
344 /* ------------------------------------------------------------------------ */
346 ipf_pool_soft_destroy(softc, arg)
347 ipf_main_softc_t *softc;
350 ipf_pool_softc_t *softp = arg;
352 ipf_rx_destroy(softp->ipf_radix);
358 /* ------------------------------------------------------------------------ */
359 /* Function: ipf_pool_node_add */
360 /* Returns: int - 0 = success, else error */
361 /* Parameters: softc(I) - pointer to soft context main structure */
362 /* arg(I) - pointer to local context to use */
363 /* op(I) - pointer to lookup operatin data */
365 /* When adding a new node, a check is made to ensure that the address/mask */
366 /* pair supplied has been appropriately prepared by applying the mask to */
367 /* the address prior to calling for the pair to be added. */
368 /* ------------------------------------------------------------------------ */
370 ipf_pool_node_add(softc, arg, op, uid)
371 ipf_main_softc_t *softc;
376 ip_pool_node_t node, *m;
380 if (op->iplo_size != sizeof(node)) {
385 err = COPYIN(op->iplo_struct, &node, sizeof(node));
391 p = ipf_pool_find(arg, op->iplo_unit, op->iplo_name);
397 if (node.ipn_addr.adf_family == AF_INET) {
398 if (node.ipn_addr.adf_len != offsetof(addrfamily_t, adf_addr) +
399 sizeof(struct in_addr)) {
405 else if (node.ipn_addr.adf_family == AF_INET6) {
406 if (node.ipn_addr.adf_len != offsetof(addrfamily_t, adf_addr) +
407 sizeof(struct in6_addr)) {
413 if (node.ipn_mask.adf_len != node.ipn_addr.adf_len) {
419 * Check that the address/mask pair works.
421 if (node.ipn_addr.adf_family == AF_INET) {
422 if ((node.ipn_addr.adf_addr.in4.s_addr &
423 node.ipn_mask.adf_addr.in4.s_addr) !=
424 node.ipn_addr.adf_addr.in4.s_addr) {
430 else if (node.ipn_addr.adf_family == AF_INET6) {
431 if (IP6_MASKNEQ(&node.ipn_addr.adf_addr.in6,
432 &node.ipn_mask.adf_addr.in6,
433 &node.ipn_addr.adf_addr.in6)) {
441 * add an entry to a pool - return an error if it already
442 * exists remove an entry from a pool - if it exists
443 * - in both cases, the pool *must* exist!
445 m = ipf_pool_findeq(arg, p, &node.ipn_addr, &node.ipn_mask);
450 err = ipf_pool_insert_node(softc, arg, p, &node);
456 /* ------------------------------------------------------------------------ */
457 /* Function: ipf_pool_node_del */
458 /* Returns: int - 0 = success, else error */
459 /* Parameters: softc(I) - pointer to soft context main structure */
460 /* arg(I) - pointer to local context to use */
461 /* op(I) - pointer to lookup operatin data */
463 /* ------------------------------------------------------------------------ */
465 ipf_pool_node_del(softc, arg, op, uid)
466 ipf_main_softc_t *softc;
471 ip_pool_node_t node, *m;
476 if (op->iplo_size != sizeof(node)) {
482 err = COPYIN(op->iplo_struct, &node, sizeof(node));
488 if (node.ipn_addr.adf_family == AF_INET) {
489 if (node.ipn_addr.adf_len != offsetof(addrfamily_t, adf_addr) +
490 sizeof(struct in_addr)) {
496 else if (node.ipn_addr.adf_family == AF_INET6) {
497 if (node.ipn_addr.adf_len != offsetof(addrfamily_t, adf_addr) +
498 sizeof(struct in6_addr)) {
504 if (node.ipn_mask.adf_len != node.ipn_addr.adf_len) {
509 p = ipf_pool_find(arg, op->iplo_unit, op->iplo_name);
515 m = ipf_pool_findeq(arg, p, &node.ipn_addr, &node.ipn_mask);
521 if ((uid != 0) && (uid != m->ipn_uid)) {
526 err = ipf_pool_remove_node(softc, arg, p, m);
532 /* ------------------------------------------------------------------------ */
533 /* Function: ipf_pool_table_add */
534 /* Returns: int - 0 = success, else error */
535 /* Parameters: softc(I) - pointer to soft context main structure */
536 /* arg(I) - pointer to local context to use */
537 /* op(I) - pointer to lookup operatin data */
539 /* ------------------------------------------------------------------------ */
541 ipf_pool_table_add(softc, arg, op)
542 ipf_main_softc_t *softc;
548 if (((op->iplo_arg & LOOKUP_ANON) == 0) &&
549 (ipf_pool_find(arg, op->iplo_unit, op->iplo_name) != NULL)) {
553 err = ipf_pool_create(softc, arg, op);
560 /* ------------------------------------------------------------------------ */
561 /* Function: ipf_pool_table_del */
562 /* Returns: int - 0 = success, else error */
563 /* Parameters: softc(I) - pointer to soft context main structure */
564 /* arg(I) - pointer to local context to use */
565 /* op(I) - pointer to lookup operatin data */
567 /* ------------------------------------------------------------------------ */
569 ipf_pool_table_del(softc, arg, op)
570 ipf_main_softc_t *softc;
574 return ipf_pool_destroy(softc, arg, op->iplo_unit, op->iplo_name);
578 /* ------------------------------------------------------------------------ */
579 /* Function: ipf_pool_statistics */
580 /* Returns: int - 0 = success, else error */
581 /* Parameters: softc(I) - pointer to soft context main structure */
582 /* arg(I) - pointer to local context to use */
583 /* op(I) - pointer to lookup operatin data */
585 /* Copy the current statistics out into user space, collecting pool list */
586 /* pointers as appropriate for later use. */
587 /* ------------------------------------------------------------------------ */
589 ipf_pool_stats_get(softc, arg, op)
590 ipf_main_softc_t *softc;
594 ipf_pool_softc_t *softp = arg;
595 ipf_pool_stat_t stats;
596 int unit, i, err = 0;
598 if (op->iplo_size != sizeof(ipf_pool_stat_t)) {
603 bcopy((char *)&softp->ipf_pool_stats, (char *)&stats, sizeof(stats));
604 unit = op->iplo_unit;
605 if (unit == IPL_LOGALL) {
606 for (i = 0; i <= LOOKUP_POOL_MAX; i++)
607 stats.ipls_list[i] = softp->ipf_pool_list[i];
608 } else if (unit >= 0 && unit <= IPL_LOGMAX) {
609 unit++; /* -1 => 0 */
610 if (op->iplo_name[0] != '\0')
611 stats.ipls_list[unit] = ipf_pool_exists(softp, unit - 1,
614 stats.ipls_list[unit] = softp->ipf_pool_list[unit];
620 err = COPYOUT(&stats, op->iplo_struct, sizeof(stats));
630 /* ------------------------------------------------------------------------ */
631 /* Function: ipf_pool_exists */
632 /* Returns: int - 0 = success, else error */
633 /* Parameters: softp(I) - pointer to soft context pool information */
634 /* unit(I) - ipfilter device to which we are working on */
635 /* name(I) - name of the pool */
637 /* Find a matching pool inside the collection of pools for a particular */
638 /* device, indicated by the unit number. */
639 /* ------------------------------------------------------------------------ */
641 ipf_pool_exists(softp, unit, name)
642 ipf_pool_softc_t *softp;
649 if (unit == IPL_LOGALL) {
650 for (i = 0; i <= LOOKUP_POOL_MAX; i++) {
651 for (p = softp->ipf_pool_list[i]; p != NULL;
653 if (strncmp(p->ipo_name, name,
654 sizeof(p->ipo_name)) == 0)
661 for (p = softp->ipf_pool_list[unit + 1]; p != NULL;
663 if (strncmp(p->ipo_name, name,
664 sizeof(p->ipo_name)) == 0)
671 /* ------------------------------------------------------------------------ */
672 /* Function: ipf_pool_find */
673 /* Returns: int - 0 = success, else error */
674 /* Parameters: arg(I) - pointer to local context to use */
675 /* unit(I) - ipfilter device to which we are working on */
676 /* name(I) - name of the pool */
678 /* Find a matching pool inside the collection of pools for a particular */
679 /* device, indicated by the unit number. If it is marked for deletion then */
680 /* pretend it does not exist. */
681 /* ------------------------------------------------------------------------ */
683 ipf_pool_find(arg, unit, name)
688 ipf_pool_softc_t *softp = arg;
691 p = ipf_pool_exists(softp, unit, name);
692 if ((p != NULL) && (p->ipo_flags & IPOOL_DELETE))
699 /* ------------------------------------------------------------------------ */
700 /* Function: ipf_pool_select_add_ref */
701 /* Returns: int - 0 = success, else error */
702 /* Parameters: arg(I) - pointer to local context to use */
703 /* unit(I) - ipfilter device to which we are working on */
704 /* name(I) - name of the pool */
706 /* ------------------------------------------------------------------------ */
708 ipf_pool_select_add_ref(arg, unit, name)
715 p = ipf_pool_find(arg, -1, name);
717 p = ipf_pool_find(arg, unit, name);
719 ATOMIC_INC32(p->ipo_ref);
725 /* ------------------------------------------------------------------------ */
726 /* Function: ipf_pool_findeq */
727 /* Returns: int - 0 = success, else error */
728 /* Parameters: softp(I) - pointer to soft context pool information */
729 /* ipo(I) - pointer to the pool getting the new node. */
730 /* addr(I) - pointer to address information to match on */
731 /* mask(I) - pointer to the address mask to match */
733 /* Searches for an exact match of an entry in the pool. */
734 /* ------------------------------------------------------------------------ */
735 extern void printhostmask(int, u_32_t *, u_32_t *);
736 static ip_pool_node_t *
737 ipf_pool_findeq(softp, ipo, addr, mask)
738 ipf_pool_softc_t *softp;
740 addrfamily_t *addr, *mask;
744 n = ipo->ipo_head->lookup(ipo->ipo_head, addr, mask);
745 return (ip_pool_node_t *)n;
749 /* ------------------------------------------------------------------------ */
750 /* Function: ipf_pool_search */
751 /* Returns: int - 0 == +ve match, -1 == error, 1 == -ve/no match */
752 /* Parameters: softc(I) - pointer to soft context main structure */
753 /* tptr(I) - pointer to the pool to search */
754 /* version(I) - IP protocol version (4 or 6) */
755 /* dptr(I) - pointer to address information */
756 /* bytes(I) - length of packet */
758 /* Search the pool for a given address and return a search result. */
759 /* ------------------------------------------------------------------------ */
761 ipf_pool_search(softc, tptr, ipversion, dptr, bytes)
762 ipf_main_softc_t *softc;
781 addr = (i6addr_t *)dptr;
782 bzero(&v, sizeof(v));
784 if (ipversion == 4) {
785 v.adf_family = AF_INET;
786 v.adf_len = offsetof(addrfamily_t, adf_addr) +
787 sizeof(struct in_addr);
788 v.adf_addr.in4 = addr->in4;
790 } else if (ipversion == 6) {
791 v.adf_family = AF_INET6;
792 v.adf_len = offsetof(addrfamily_t, adf_addr) +
793 sizeof(struct in6_addr);
794 v.adf_addr.in6 = addr->in6;
799 READ_ENTER(&softc->ipf_poolrw);
801 rn = ipo->ipo_head->matchaddr(ipo->ipo_head, &v);
803 if ((rn != NULL) && (rn->root == 0)) {
804 m = (ip_pool_node_t *)rn;
806 m->ipn_bytes += bytes;
810 RWLOCK_EXIT(&softc->ipf_poolrw);
815 /* ------------------------------------------------------------------------ */
816 /* Function: ipf_pool_insert_node */
817 /* Returns: int - 0 = success, else error */
818 /* Parameters: softc(I) - pointer to soft context main structure */
819 /* softp(I) - pointer to soft context pool information */
820 /* ipo(I) - pointer to the pool getting the new node. */
821 /* node(I) - structure with address/mask to add */
822 /* Locks: WRITE(ipf_poolrw) */
824 /* Add another node to the pool given by ipo. The three parameters passed */
825 /* in (addr, mask, info) shold all be stored in the node. */
826 /* ------------------------------------------------------------------------ */
828 ipf_pool_insert_node(softc, softp, ipo, node)
829 ipf_main_softc_t *softc;
830 ipf_pool_softc_t *softp;
832 struct ip_pool_node *node;
837 if ((node->ipn_addr.adf_len > sizeof(*rn)) ||
838 (node->ipn_addr.adf_len < 4)) {
843 if ((node->ipn_mask.adf_len > sizeof(*rn)) ||
844 (node->ipn_mask.adf_len < 4)) {
849 KMALLOC(x, ip_pool_node_t *);
856 bzero((char *)x->ipn_nodes, sizeof(x->ipn_nodes));
862 x->ipn_pdnext = NULL;
864 if (x->ipn_die != 0) {
866 * If the new node has a given expiration time, insert it
867 * into the list of expiring nodes with the ones to be
868 * removed first added to the front of the list. The
869 * insertion is O(n) but it is kept sorted for quick scans
870 * at expiration interval checks.
874 x->ipn_die = softc->ipf_ticks + IPF_TTLVAL(x->ipn_die);
875 for (n = softp->ipf_node_explist; n != NULL; n = n->ipn_dnext) {
876 if (x->ipn_die < n->ipn_die)
878 if (n->ipn_dnext == NULL) {
880 * We've got to the last node and everything
881 * wanted to be expired before this new node,
882 * so we have to tack it on the end...
885 x->ipn_pdnext = &n->ipn_dnext;
891 if (softp->ipf_node_explist == NULL) {
892 softp->ipf_node_explist = x;
893 x->ipn_pdnext = &softp->ipf_node_explist;
894 } else if (n != NULL) {
896 x->ipn_pdnext = n->ipn_pdnext;
897 n->ipn_pdnext = &x->ipn_dnext;
901 rn = ipo->ipo_head->addaddr(ipo->ipo_head, &x->ipn_addr, &x->ipn_mask,
904 printf("Added %p at %p\n", x, rn);
914 x->ipn_pnext = ipo->ipo_tail;
916 ipo->ipo_tail = &x->ipn_next;
918 softp->ipf_pool_stats.ipls_nodes++;
924 /* ------------------------------------------------------------------------ */
925 /* Function: ipf_pool_create */
926 /* Returns: int - 0 = success, else error */
927 /* Parameters: softc(I) - pointer to soft context main structure */
928 /* softp(I) - pointer to soft context pool information */
929 /* op(I) - pointer to iplookup struct with call details */
930 /* Locks: WRITE(ipf_poolrw) */
932 /* Creates a new group according to the paramters passed in via the */
933 /* iplookupop structure. Does not check to see if the group already exists */
934 /* when being inserted - assume this has already been done. If the pool is */
935 /* marked as being anonymous, give it a new, unique, identifier. Call any */
936 /* other functions required to initialise the structure. */
938 /* If the structure is flagged for deletion then reset the flag and return, */
939 /* as this likely means we've tried to free a pool that is in use (flush) */
940 /* and now want to repopulate it with "new" data. */
941 /* ------------------------------------------------------------------------ */
943 ipf_pool_create(softc, softp, op)
944 ipf_main_softc_t *softc;
945 ipf_pool_softc_t *softp;
948 char name[FR_GROUPLEN];
952 unit = op->iplo_unit;
954 if ((op->iplo_arg & LOOKUP_ANON) == 0) {
955 h = ipf_pool_exists(softp, unit, op->iplo_name);
957 if ((h->ipo_flags & IPOOL_DELETE) == 0) {
961 h->ipo_flags &= ~IPOOL_DELETE;
966 KMALLOC(h, ip_pool_t *);
971 bzero(h, sizeof(*h));
973 if (ipf_rx_inithead(softp->ipf_radix, &h->ipo_head) != 0) {
979 if ((op->iplo_arg & LOOKUP_ANON) != 0) {
982 h->ipo_flags |= IPOOL_ANON;
983 poolnum = LOOKUP_ANON;
985 (void)snprintf(name, sizeof(name), "%x", poolnum);
987 for (p = softp->ipf_pool_list[unit + 1]; p != NULL; ) {
988 if (strncmp(name, p->ipo_name,
989 sizeof(p->ipo_name)) == 0) {
991 (void)snprintf(name, sizeof(name), "%x", poolnum);
992 p = softp->ipf_pool_list[unit + 1];
997 (void)strncpy(h->ipo_name, name, sizeof(h->ipo_name));
998 (void)strncpy(op->iplo_name, name, sizeof(op->iplo_name));
1000 (void)strncpy(h->ipo_name, op->iplo_name, sizeof(h->ipo_name));
1003 h->ipo_radix = softp->ipf_radix;
1006 h->ipo_tail = &h->ipo_list;
1008 h->ipo_next = softp->ipf_pool_list[unit + 1];
1009 if (softp->ipf_pool_list[unit + 1] != NULL)
1010 softp->ipf_pool_list[unit + 1]->ipo_pnext = &h->ipo_next;
1011 h->ipo_pnext = &softp->ipf_pool_list[unit + 1];
1012 softp->ipf_pool_list[unit + 1] = h;
1014 softp->ipf_pool_stats.ipls_pools++;
1020 /* ------------------------------------------------------------------------ */
1021 /* Function: ipf_pool_remove_node */
1022 /* Returns: int - 0 = success, else error */
1023 /* Parameters: softc(I) - pointer to soft context main structure */
1024 /* ipo(I) - pointer to the pool to remove the node from. */
1025 /* ipe(I) - address being deleted as a node */
1026 /* Locks: WRITE(ipf_poolrw) */
1028 /* Remove a node from the pool given by ipo. */
1029 /* ------------------------------------------------------------------------ */
1031 ipf_pool_remove_node(softc, softp, ipo, ipe)
1032 ipf_main_softc_t *softc;
1033 ipf_pool_softc_t *softp;
1035 ip_pool_node_t *ipe;
1039 if (ipo->ipo_tail == &ipe->ipn_next)
1040 ipo->ipo_tail = ipe->ipn_pnext;
1042 if (ipe->ipn_pnext != NULL)
1043 *ipe->ipn_pnext = ipe->ipn_next;
1044 if (ipe->ipn_next != NULL)
1045 ipe->ipn_next->ipn_pnext = ipe->ipn_pnext;
1047 if (ipe->ipn_pdnext != NULL)
1048 *ipe->ipn_pdnext = ipe->ipn_dnext;
1049 if (ipe->ipn_dnext != NULL)
1050 ipe->ipn_dnext->ipn_pdnext = ipe->ipn_pdnext;
1052 ptr = ipo->ipo_head->deladdr(ipo->ipo_head, &ipe->ipn_addr,
1056 ipf_pool_node_deref(softp, ipe);
1064 /* ------------------------------------------------------------------------ */
1065 /* Function: ipf_pool_destroy */
1066 /* Returns: int - 0 = success, else error */
1067 /* Parameters: softc(I) - pointer to soft context main structure */
1068 /* softp(I) - pointer to soft context pool information */
1069 /* unit(I) - ipfilter device to which we are working on */
1070 /* name(I) - name of the pool */
1071 /* Locks: WRITE(ipf_poolrw) or WRITE(ipf_global) */
1073 /* Search for a pool using paramters passed in and if it's not otherwise */
1074 /* busy, free it. If it is busy, clear all of its nodes, mark it for being */
1075 /* deleted and return an error saying it is busy. */
1077 /* NOTE: Because this function is called out of ipfdetach() where ipf_poolrw*/
1078 /* may not be initialised, we can't use an ASSERT to enforce the locking */
1079 /* assertion that one of the two (ipf_poolrw,ipf_global) is held. */
1080 /* ------------------------------------------------------------------------ */
1082 ipf_pool_destroy(softc, softp, unit, name)
1083 ipf_main_softc_t *softc;
1084 ipf_pool_softc_t *softp;
1090 ipo = ipf_pool_exists(softp, unit, name);
1096 if (ipo->ipo_ref != 1) {
1097 ipf_pool_clearnodes(softc, softp, ipo);
1098 ipo->ipo_flags |= IPOOL_DELETE;
1102 ipf_pool_free(softc, softp, ipo);
1107 /* ------------------------------------------------------------------------ */
1108 /* Function: ipf_pool_flush */
1109 /* Returns: int - number of pools deleted */
1110 /* Parameters: softc(I) - pointer to soft context main structure */
1111 /* arg(I) - pointer to local context to use */
1112 /* fp(I) - which pool(s) to flush */
1113 /* Locks: WRITE(ipf_poolrw) or WRITE(ipf_global) */
1115 /* Free all pools associated with the device that matches the unit number */
1116 /* passed in with operation. */
1118 /* NOTE: Because this function is called out of ipfdetach() where ipf_poolrw*/
1119 /* may not be initialised, we can't use an ASSERT to enforce the locking */
1120 /* assertion that one of the two (ipf_poolrw,ipf_global) is held. */
1121 /* ------------------------------------------------------------------------ */
1123 ipf_pool_flush(softc, arg, fp)
1124 ipf_main_softc_t *softc;
1126 iplookupflush_t *fp;
1128 ipf_pool_softc_t *softp = arg;
1129 int i, num = 0, unit, err;
1132 unit = fp->iplf_unit;
1133 for (i = -1; i <= IPL_LOGMAX; i++) {
1134 if (unit != IPLT_ALL && i != unit)
1136 for (q = softp->ipf_pool_list[i + 1]; (p = q) != NULL; ) {
1138 err = ipf_pool_destroy(softc, softp, i, p->ipo_name);
1147 /* ------------------------------------------------------------------------ */
1148 /* Function: ipf_pool_free */
1150 /* Parameters: softc(I) - pointer to soft context main structure */
1151 /* softp(I) - pointer to soft context pool information */
1152 /* ipo(I) - pointer to pool structure */
1153 /* Locks: WRITE(ipf_poolrw) or WRITE(ipf_global) */
1155 /* Deletes the pool strucutre passed in from the list of pools and deletes */
1156 /* all of the address information stored in it, including any tree data */
1157 /* structures also allocated. */
1159 /* NOTE: Because this function is called out of ipfdetach() where ipf_poolrw*/
1160 /* may not be initialised, we can't use an ASSERT to enforce the locking */
1161 /* assertion that one of the two (ipf_poolrw,ipf_global) is held. */
1162 /* ------------------------------------------------------------------------ */
1164 ipf_pool_free(softc, softp, ipo)
1165 ipf_main_softc_t *softc;
1166 ipf_pool_softc_t *softp;
1170 ipf_pool_clearnodes(softc, softp, ipo);
1172 if (ipo->ipo_next != NULL)
1173 ipo->ipo_next->ipo_pnext = ipo->ipo_pnext;
1174 *ipo->ipo_pnext = ipo->ipo_next;
1175 ipf_rx_freehead(ipo->ipo_head);
1178 softp->ipf_pool_stats.ipls_pools--;
1182 /* ------------------------------------------------------------------------ */
1183 /* Function: ipf_pool_clearnodes */
1185 /* Parameters: softc(I) - pointer to soft context main structure */
1186 /* softp(I) - pointer to soft context pool information */
1187 /* ipo(I) - pointer to pool structure */
1188 /* Locks: WRITE(ipf_poolrw) or WRITE(ipf_global) */
1190 /* Deletes all nodes stored in a pool structure. */
1191 /* ------------------------------------------------------------------------ */
1193 ipf_pool_clearnodes(softc, softp, ipo)
1194 ipf_main_softc_t *softc;
1195 ipf_pool_softc_t *softp;
1198 ip_pool_node_t *n, **next;
1200 for (next = &ipo->ipo_list; (n = *next) != NULL; )
1201 ipf_pool_remove_node(softc, softp, ipo, n);
1203 ipo->ipo_list = NULL;
1207 /* ------------------------------------------------------------------------ */
1208 /* Function: ipf_pool_deref */
1210 /* Parameters: softc(I) - pointer to soft context main structure */
1211 /* arg(I) - pointer to local context to use */
1212 /* pool(I) - pointer to pool structure */
1213 /* Locks: WRITE(ipf_poolrw) */
1215 /* Drop the number of known references to this pool structure by one and if */
1216 /* we arrive at zero known references, free it. */
1217 /* ------------------------------------------------------------------------ */
1219 ipf_pool_deref(softc, arg, pool)
1220 ipf_main_softc_t *softc;
1223 ip_pool_t *ipo = pool;
1227 if (ipo->ipo_ref == 0)
1228 ipf_pool_free(softc, arg, ipo);
1230 else if ((ipo->ipo_ref == 1) && (ipo->ipo_flags & IPOOL_DELETE))
1231 ipf_pool_destroy(softc, arg, ipo->ipo_unit, ipo->ipo_name);
1237 /* ------------------------------------------------------------------------ */
1238 /* Function: ipf_pool_node_deref */
1240 /* Parameters: softp(I) - pointer to soft context pool information */
1241 /* ipn(I) - pointer to pool structure */
1242 /* Locks: WRITE(ipf_poolrw) */
1244 /* Drop a reference to the pool node passed in and if we're the last, free */
1245 /* it all up and adjust the stats accordingly. */
1246 /* ------------------------------------------------------------------------ */
1248 ipf_pool_node_deref(softp, ipn)
1249 ipf_pool_softc_t *softp;
1250 ip_pool_node_t *ipn;
1255 if (ipn->ipn_ref == 0) {
1257 softp->ipf_pool_stats.ipls_nodes--;
1262 /* ------------------------------------------------------------------------ */
1263 /* Function: ipf_pool_iter_next */
1265 /* Parameters: softc(I) - pointer to soft context main structure */
1266 /* arg(I) - pointer to local context to use */
1267 /* token(I) - pointer to pool structure */
1268 /* ilp(IO) - pointer to pool iterating structure */
1270 /* ------------------------------------------------------------------------ */
1272 ipf_pool_iter_next(softc, arg, token, ilp)
1273 ipf_main_softc_t *softc;
1276 ipflookupiter_t *ilp;
1278 ipf_pool_softc_t *softp = arg;
1279 ip_pool_node_t *node, zn, *nextnode;
1280 ip_pool_t *ipo, zp, *nextipo;
1290 READ_ENTER(&softc->ipf_poolrw);
1292 switch (ilp->ili_otype)
1294 case IPFLOOKUPITER_LIST :
1295 ipo = token->ipt_data;
1297 nextipo = softp->ipf_pool_list[(int)ilp->ili_unit + 1];
1299 nextipo = ipo->ipo_next;
1302 if (nextipo != NULL) {
1303 ATOMIC_INC32(nextipo->ipo_ref);
1304 token->ipt_data = nextipo;
1306 bzero((char *)&zp, sizeof(zp));
1308 token->ipt_data = NULL;
1310 pnext = nextipo->ipo_next;
1313 case IPFLOOKUPITER_NODE :
1314 node = token->ipt_data;
1316 ipo = ipf_pool_exists(arg, ilp->ili_unit,
1322 nextnode = ipo->ipo_list;
1326 nextnode = node->ipn_next;
1329 if (nextnode != NULL) {
1330 ATOMIC_INC32(nextnode->ipn_ref);
1331 token->ipt_data = nextnode;
1333 bzero((char *)&zn, sizeof(zn));
1335 token->ipt_data = NULL;
1337 pnext = nextnode->ipn_next;
1347 RWLOCK_EXIT(&softc->ipf_poolrw);
1351 switch (ilp->ili_otype)
1353 case IPFLOOKUPITER_LIST :
1354 err = COPYOUT(nextipo, ilp->ili_data, sizeof(*nextipo));
1360 WRITE_ENTER(&softc->ipf_poolrw);
1361 ipf_pool_deref(softc, softp, ipo);
1362 RWLOCK_EXIT(&softc->ipf_poolrw);
1366 case IPFLOOKUPITER_NODE :
1367 err = COPYOUT(nextnode, ilp->ili_data, sizeof(*nextnode));
1373 WRITE_ENTER(&softc->ipf_poolrw);
1374 ipf_pool_node_deref(softp, node);
1375 RWLOCK_EXIT(&softc->ipf_poolrw);
1380 ipf_token_mark_complete(token);
1386 /* ------------------------------------------------------------------------ */
1387 /* Function: ipf_pool_iterderef */
1389 /* Parameters: softc(I) - pointer to soft context main structure */
1390 /* arg(I) - pointer to local context to use */
1391 /* unit(I) - ipfilter device to which we are working on */
1392 /* Locks: WRITE(ipf_poolrw) */
1394 /* ------------------------------------------------------------------------ */
1396 ipf_pool_iter_deref(softc, arg, otype, unit, data)
1397 ipf_main_softc_t *softc;
1403 ipf_pool_softc_t *softp = arg;
1408 if (unit < 0 || unit > IPL_LOGMAX)
1413 case IPFLOOKUPITER_LIST :
1414 ipf_pool_deref(softc, softp, (ip_pool_t *)data);
1417 case IPFLOOKUPITER_NODE :
1418 ipf_pool_node_deref(softp, (ip_pool_node_t *)data);
1428 /* ------------------------------------------------------------------------ */
1429 /* Function: ipf_pool_expire */
1431 /* Parameters: softc(I) - pointer to soft context main structure */
1432 /* arg(I) - pointer to local context to use */
1434 /* At present this function exists just to support temporary addition of */
1435 /* nodes to the address pool. */
1436 /* ------------------------------------------------------------------------ */
1438 ipf_pool_expire(softc, arg)
1439 ipf_main_softc_t *softc;
1442 ipf_pool_softc_t *softp = arg;
1445 while ((n = softp->ipf_node_explist) != NULL) {
1447 * Because the list is kept sorted on insertion, the fist
1448 * one that dies in the future means no more work to do.
1450 if (n->ipn_die > softc->ipf_ticks)
1452 ipf_pool_remove_node(softc, softp, n->ipn_owner, n);
1461 ipf_pool_dump(softc, arg)
1462 ipf_main_softc_t *softc;
1465 ipf_pool_softc_t *softp = arg;
1469 printf("List of configured pools\n");
1470 for (i = 0; i <= LOOKUP_POOL_MAX; i++)
1471 for (ipl = softp->ipf_pool_list[i]; ipl != NULL;
1472 ipl = ipl->ipo_next)
1473 printpool(ipl, bcopywrap, NULL, opts, NULL);