2 * Copyright (C) 2012 by Darren Reed.
4 * See the IPFILTER.LICENCE file for details on licencing.
6 #if defined(KERNEL) || defined(_KERNEL)
13 # define _PROTO_NET_H_
15 #include <sys/errno.h>
16 #include <sys/types.h>
17 #include <sys/param.h>
19 #if !defined(_KERNEL) && !defined(__KERNEL__)
30 # include <sys/systm.h>
31 # if defined(NetBSD) && (__NetBSD_Version__ >= 104000000)
32 # include <sys/proc.h>
36 #if defined(_KERNEL) && !defined(SOLARIS2)
37 # include <sys/mbuf.h>
39 #if defined(__SVR4) || defined(__svr4__)
40 # include <sys/byteorder.h>
42 # include <sys/dditypes.h>
44 # include <sys/stream.h>
45 # include <sys/kmem.h>
47 #if defined(__FreeBSD_version) && (__FreeBSD_version >= 300000)
48 # include <sys/malloc.h>
51 #include <sys/socket.h>
53 #include <netinet/in.h>
58 #include "netinet/ip_compat.h"
59 #include "netinet/ip_fil.h"
60 #include "netinet/ip_pool.h"
61 #include "netinet/radix_ipf.h"
66 static const char sccsid[] = "@(#)ip_fil.c 2.41 6/5/96 (C) 1993-2000 Darren Reed";
67 static const char rcsid[] = "@(#)$Id$";
70 typedef struct ipf_pool_softc_s {
72 ip_pool_t *ipf_pool_list[LOOKUP_POOL_SZ];
73 ipf_pool_stat_t ipf_pool_stats;
74 ip_pool_node_t *ipf_node_explist;
78 static void ipf_pool_clearnodes __P((ipf_main_softc_t *, ipf_pool_softc_t *,
80 static int ipf_pool_create __P((ipf_main_softc_t *, ipf_pool_softc_t *, iplookupop_t *));
81 static int ipf_pool_deref __P((ipf_main_softc_t *, void *, void *));
82 static int ipf_pool_destroy __P((ipf_main_softc_t *, ipf_pool_softc_t *, int, char *));
83 static void *ipf_pool_exists __P((ipf_pool_softc_t *, int, char *));
84 static void *ipf_pool_find __P((void *, int, char *));
85 static ip_pool_node_t *ipf_pool_findeq __P((ipf_pool_softc_t *, ip_pool_t *,
86 addrfamily_t *, addrfamily_t *));
87 static void ipf_pool_free __P((ipf_main_softc_t *, ipf_pool_softc_t *,
89 static int ipf_pool_insert_node __P((ipf_main_softc_t *, ipf_pool_softc_t *,
90 ip_pool_t *, struct ip_pool_node *));
91 static int ipf_pool_iter_deref __P((ipf_main_softc_t *, void *, int, int, void *));
92 static int ipf_pool_iter_next __P((ipf_main_softc_t *, void *, ipftoken_t *,
94 static size_t ipf_pool_flush __P((ipf_main_softc_t *, void *, iplookupflush_t *));
95 static int ipf_pool_node_add __P((ipf_main_softc_t *, void *, iplookupop_t *,
97 static int ipf_pool_node_del __P((ipf_main_softc_t *, void *, iplookupop_t *,
99 static void ipf_pool_node_deref __P((ipf_pool_softc_t *, ip_pool_node_t *));
100 static int ipf_pool_remove_node __P((ipf_main_softc_t *, ipf_pool_softc_t *,
101 ip_pool_t *, ip_pool_node_t *));
102 static int ipf_pool_search __P((ipf_main_softc_t *, void *, int,
104 static void *ipf_pool_soft_create __P((ipf_main_softc_t *));
105 static void ipf_pool_soft_destroy __P((ipf_main_softc_t *, void *));
106 static void ipf_pool_soft_fini __P((ipf_main_softc_t *, void *));
107 static int ipf_pool_soft_init __P((ipf_main_softc_t *, void *));
108 static int ipf_pool_stats_get __P((ipf_main_softc_t *, void *, iplookupop_t *));
109 static int ipf_pool_table_add __P((ipf_main_softc_t *, void *, iplookupop_t *));
110 static int ipf_pool_table_del __P((ipf_main_softc_t *, void *, iplookupop_t *));
111 static void *ipf_pool_select_add_ref __P((void *, int, char *));
112 static void ipf_pool_expire __P((ipf_main_softc_t *, void *));
114 ipf_lookup_t ipf_pool_backend = {
116 ipf_pool_soft_create,
117 ipf_pool_soft_destroy,
131 ipf_pool_select_add_ref,
139 void treeprint __P((ip_pool_t *));
152 RWLOCK_INIT(softc->ipf_poolrw, "poolrw");
155 bzero((char *)&ip, sizeof(ip));
156 bzero((char *)&op, sizeof(op));
157 bzero((char *)&node, sizeof(node));
158 strcpy(op.iplo_name, "0");
160 if (ipf_pool_create(&op) == 0)
161 ipo = ipf_pool_exists(0, "0");
163 node.ipn_addr.adf_family = AF_INET;
165 node.ipn_addr.adf_addr.in4.s_addr = 0x0a010203;
166 node.ipn_mask.adf_addr.in4.s_addr = 0xffffffff;
168 ipf_pool_insert_node(ipo, &node);
170 node.ipn_addr.adf_addr.in4.s_addr = 0x0a000000;
171 node.ipn_mask.adf_addr.in4.s_addr = 0xff000000;
173 ipf_pool_insert_node(ipo, &node);
175 node.ipn_addr.adf_addr.in4.s_addr = 0x0a010100;
176 node.ipn_mask.adf_addr.in4.s_addr = 0xffffff00;
178 ipf_pool_insert_node(ipo, &node);
180 node.ipn_addr.adf_addr.in4.s_addr = 0x0a010200;
181 node.ipn_mask.adf_addr.in4.s_addr = 0xffffff00;
183 ipf_pool_insert_node(ipo, &node);
185 node.ipn_addr.adf_addr.in4.s_addr = 0x0a010000;
186 node.ipn_mask.adf_addr.in4.s_addr = 0xffff0000;
188 ipf_pool_insert_node(ipo, &node);
190 node.ipn_addr.adf_addr.in4.s_addr = 0x0a01020f;
191 node.ipn_mask.adf_addr.in4.s_addr = 0xffffffff;
193 ipf_pool_insert_node(ipo, &node);
197 ip.in4.s_addr = 0x0a00aabb;
198 printf("search(%#x) = %d (0)\n", ip.in4.s_addr,
199 ipf_pool_search(ipo, 4, &ip, 1));
201 ip.in4.s_addr = 0x0a000001;
202 printf("search(%#x) = %d (0)\n", ip.in4.s_addr,
203 ipf_pool_search(ipo, 4, &ip, 1));
205 ip.in4.s_addr = 0x0a000101;
206 printf("search(%#x) = %d (0)\n", ip.in4.s_addr,
207 ipf_pool_search(ipo, 4, &ip, 1));
209 ip.in4.s_addr = 0x0a010001;
210 printf("search(%#x) = %d (1)\n", ip.in4.s_addr,
211 ipf_pool_search(ipo, 4, &ip, 1));
213 ip.in4.s_addr = 0x0a010101;
214 printf("search(%#x) = %d (1)\n", ip.in4.s_addr,
215 ipf_pool_search(ipo, 4, &ip, 1));
217 ip.in4.s_addr = 0x0a010201;
218 printf("search(%#x) = %d (0)\n", ip.in4.s_addr,
219 ipf_pool_search(ipo, 4, &ip, 1));
221 ip.in4.s_addr = 0x0a010203;
222 printf("search(%#x) = %d (1)\n", ip.in4.s_addr,
223 ipf_pool_search(ipo, 4, &ip, 1));
225 ip.in4.s_addr = 0x0a01020f;
226 printf("search(%#x) = %d (1)\n", ip.in4.s_addr,
227 ipf_pool_search(ipo, 4, &ip, 1));
229 ip.in4.s_addr = 0x0b00aabb;
230 printf("search(%#x) = %d (-1)\n", ip.in4.s_addr,
231 ipf_pool_search(ipo, 4, &ip, 1));
249 for (c = ipo->ipo_list; c != NULL; c = c->ipn_next)
250 printf("Node %p(%s) (%#x/%#x) = %d hits %lu\n",
251 c, c->ipn_name, c->ipn_addr.adf_addr.in4.s_addr,
252 c->ipn_mask.adf_addr.in4.s_addr,
253 c->ipn_info, c->ipn_hits);
255 #endif /* TEST_POOL */
258 /* ------------------------------------------------------------------------ */
259 /* Function: ipf_pool_soft_create */
260 /* Returns: void * - NULL = failure, else pointer to local context */
261 /* Parameters: softc(I) - pointer to soft context main structure */
263 /* Initialise the routing table data structures where required. */
264 /* ------------------------------------------------------------------------ */
266 ipf_pool_soft_create(softc)
267 ipf_main_softc_t *softc;
269 ipf_pool_softc_t *softp;
271 KMALLOC(softp, ipf_pool_softc_t *);
277 bzero((char *)softp, sizeof(*softp));
279 softp->ipf_radix = ipf_rx_create();
280 if (softp->ipf_radix == NULL) {
290 /* ------------------------------------------------------------------------ */
291 /* Function: ipf_pool_soft_init */
292 /* Returns: int - 0 = success, else error */
293 /* Parameters: softc(I) - pointer to soft context main structure */
294 /* arg(I) - pointer to local context to use */
296 /* Initialise the routing table data structures where required. */
297 /* ------------------------------------------------------------------------ */
299 ipf_pool_soft_init(softc, arg)
300 ipf_main_softc_t *softc;
303 ipf_pool_softc_t *softp = arg;
305 ipf_rx_init(softp->ipf_radix);
311 /* ------------------------------------------------------------------------ */
312 /* Function: ipf_pool_soft_fini */
314 /* Parameters: softc(I) - pointer to soft context main structure */
315 /* arg(I) - pointer to local context to use */
316 /* Locks: WRITE(ipf_global) */
318 /* Clean up all the pool data structures allocated and call the cleanup */
319 /* function for the radix tree that supports the pools. ipf_pool_destroy is */
320 /* used to delete the pools one by one to ensure they're properly freed up. */
321 /* ------------------------------------------------------------------------ */
323 ipf_pool_soft_fini(softc, arg)
324 ipf_main_softc_t *softc;
327 ipf_pool_softc_t *softp = arg;
333 for (i = -1; i <= IPL_LOGMAX; i++) {
334 for (q = softp->ipf_pool_list[i + 1]; (p = q) != NULL; ) {
336 (void) ipf_pool_destroy(softc, arg, i, p->ipo_name);
342 /* ------------------------------------------------------------------------ */
343 /* Function: ipf_pool_soft_destroy */
345 /* Parameters: softc(I) - pointer to soft context main structure */
346 /* arg(I) - pointer to local context to use */
348 /* Clean up the pool by free'ing the radix tree associated with it and free */
349 /* up the pool context too. */
350 /* ------------------------------------------------------------------------ */
352 ipf_pool_soft_destroy(softc, arg)
353 ipf_main_softc_t *softc;
356 ipf_pool_softc_t *softp = arg;
358 ipf_rx_destroy(softp->ipf_radix);
364 /* ------------------------------------------------------------------------ */
365 /* Function: ipf_pool_node_add */
366 /* Returns: int - 0 = success, else error */
367 /* Parameters: softc(I) - pointer to soft context main structure */
368 /* arg(I) - pointer to local context to use */
369 /* op(I) - pointer to lookup operatin data */
371 /* When adding a new node, a check is made to ensure that the address/mask */
372 /* pair supplied has been appropriately prepared by applying the mask to */
373 /* the address prior to calling for the pair to be added. */
374 /* ------------------------------------------------------------------------ */
376 ipf_pool_node_add(softc, arg, op, uid)
377 ipf_main_softc_t *softc;
382 ip_pool_node_t node, *m;
386 if (op->iplo_size != sizeof(node)) {
391 err = COPYIN(op->iplo_struct, &node, sizeof(node));
397 p = ipf_pool_find(arg, op->iplo_unit, op->iplo_name);
403 if (node.ipn_addr.adf_family == AF_INET) {
404 if (node.ipn_addr.adf_len != offsetof(addrfamily_t, adf_addr) +
405 sizeof(struct in_addr)) {
411 else if (node.ipn_addr.adf_family == AF_INET6) {
412 if (node.ipn_addr.adf_len != offsetof(addrfamily_t, adf_addr) +
413 sizeof(struct in6_addr)) {
419 if (node.ipn_mask.adf_len != node.ipn_addr.adf_len) {
425 * Check that the address/mask pair works.
427 if (node.ipn_addr.adf_family == AF_INET) {
428 if ((node.ipn_addr.adf_addr.in4.s_addr &
429 node.ipn_mask.adf_addr.in4.s_addr) !=
430 node.ipn_addr.adf_addr.in4.s_addr) {
436 else if (node.ipn_addr.adf_family == AF_INET6) {
437 if (IP6_MASKNEQ(&node.ipn_addr.adf_addr.in6,
438 &node.ipn_mask.adf_addr.in6,
439 &node.ipn_addr.adf_addr.in6)) {
447 * add an entry to a pool - return an error if it already
448 * exists remove an entry from a pool - if it exists
449 * - in both cases, the pool *must* exist!
451 m = ipf_pool_findeq(arg, p, &node.ipn_addr, &node.ipn_mask);
456 err = ipf_pool_insert_node(softc, arg, p, &node);
462 /* ------------------------------------------------------------------------ */
463 /* Function: ipf_pool_node_del */
464 /* Returns: int - 0 = success, else error */
465 /* Parameters: softc(I) - pointer to soft context main structure */
466 /* arg(I) - pointer to local context to use */
467 /* op(I) - pointer to lookup operatin data */
469 /* ------------------------------------------------------------------------ */
471 ipf_pool_node_del(softc, arg, op, uid)
472 ipf_main_softc_t *softc;
477 ip_pool_node_t node, *m;
482 if (op->iplo_size != sizeof(node)) {
488 err = COPYIN(op->iplo_struct, &node, sizeof(node));
494 if (node.ipn_addr.adf_family == AF_INET) {
495 if (node.ipn_addr.adf_len != offsetof(addrfamily_t, adf_addr) +
496 sizeof(struct in_addr)) {
502 else if (node.ipn_addr.adf_family == AF_INET6) {
503 if (node.ipn_addr.adf_len != offsetof(addrfamily_t, adf_addr) +
504 sizeof(struct in6_addr)) {
510 if (node.ipn_mask.adf_len != node.ipn_addr.adf_len) {
515 p = ipf_pool_find(arg, op->iplo_unit, op->iplo_name);
521 m = ipf_pool_findeq(arg, p, &node.ipn_addr, &node.ipn_mask);
527 if ((uid != 0) && (uid != m->ipn_uid)) {
532 err = ipf_pool_remove_node(softc, arg, p, m);
538 /* ------------------------------------------------------------------------ */
539 /* Function: ipf_pool_table_add */
540 /* Returns: int - 0 = success, else error */
541 /* Parameters: softc(I) - pointer to soft context main structure */
542 /* arg(I) - pointer to local context to use */
543 /* op(I) - pointer to lookup operatin data */
545 /* ------------------------------------------------------------------------ */
547 ipf_pool_table_add(softc, arg, op)
548 ipf_main_softc_t *softc;
554 if (((op->iplo_arg & LOOKUP_ANON) == 0) &&
555 (ipf_pool_find(arg, op->iplo_unit, op->iplo_name) != NULL)) {
559 err = ipf_pool_create(softc, arg, op);
566 /* ------------------------------------------------------------------------ */
567 /* Function: ipf_pool_table_del */
568 /* Returns: int - 0 = success, else error */
569 /* Parameters: softc(I) - pointer to soft context main structure */
570 /* arg(I) - pointer to local context to use */
571 /* op(I) - pointer to lookup operatin data */
573 /* ------------------------------------------------------------------------ */
575 ipf_pool_table_del(softc, arg, op)
576 ipf_main_softc_t *softc;
580 return ipf_pool_destroy(softc, arg, op->iplo_unit, op->iplo_name);
584 /* ------------------------------------------------------------------------ */
585 /* Function: ipf_pool_statistics */
586 /* Returns: int - 0 = success, else error */
587 /* Parameters: softc(I) - pointer to soft context main structure */
588 /* arg(I) - pointer to local context to use */
589 /* op(I) - pointer to lookup operatin data */
591 /* Copy the current statistics out into user space, collecting pool list */
592 /* pointers as appropriate for later use. */
593 /* ------------------------------------------------------------------------ */
595 ipf_pool_stats_get(softc, arg, op)
596 ipf_main_softc_t *softc;
600 ipf_pool_softc_t *softp = arg;
601 ipf_pool_stat_t stats;
602 int unit, i, err = 0;
604 if (op->iplo_size != sizeof(ipf_pool_stat_t)) {
609 bcopy((char *)&softp->ipf_pool_stats, (char *)&stats, sizeof(stats));
610 unit = op->iplo_unit;
611 if (unit == IPL_LOGALL) {
612 for (i = 0; i <= LOOKUP_POOL_MAX; i++)
613 stats.ipls_list[i] = softp->ipf_pool_list[i];
614 } else if (unit >= 0 && unit <= IPL_LOGMAX) {
615 unit++; /* -1 => 0 */
616 if (op->iplo_name[0] != '\0')
617 stats.ipls_list[unit] = ipf_pool_exists(softp, unit - 1,
620 stats.ipls_list[unit] = softp->ipf_pool_list[unit];
626 err = COPYOUT(&stats, op->iplo_struct, sizeof(stats));
636 /* ------------------------------------------------------------------------ */
637 /* Function: ipf_pool_exists */
638 /* Returns: int - 0 = success, else error */
639 /* Parameters: softp(I) - pointer to soft context pool information */
640 /* unit(I) - ipfilter device to which we are working on */
641 /* name(I) - name of the pool */
643 /* Find a matching pool inside the collection of pools for a particular */
644 /* device, indicated by the unit number. */
645 /* ------------------------------------------------------------------------ */
647 ipf_pool_exists(softp, unit, name)
648 ipf_pool_softc_t *softp;
655 if (unit == IPL_LOGALL) {
656 for (i = 0; i <= LOOKUP_POOL_MAX; i++) {
657 for (p = softp->ipf_pool_list[i]; p != NULL;
659 if (strncmp(p->ipo_name, name,
660 sizeof(p->ipo_name)) == 0)
667 for (p = softp->ipf_pool_list[unit + 1]; p != NULL;
669 if (strncmp(p->ipo_name, name,
670 sizeof(p->ipo_name)) == 0)
677 /* ------------------------------------------------------------------------ */
678 /* Function: ipf_pool_find */
679 /* Returns: int - 0 = success, else error */
680 /* Parameters: arg(I) - pointer to local context to use */
681 /* unit(I) - ipfilter device to which we are working on */
682 /* name(I) - name of the pool */
684 /* Find a matching pool inside the collection of pools for a particular */
685 /* device, indicated by the unit number. If it is marked for deletion then */
686 /* pretend it does not exist. */
687 /* ------------------------------------------------------------------------ */
689 ipf_pool_find(arg, unit, name)
694 ipf_pool_softc_t *softp = arg;
697 p = ipf_pool_exists(softp, unit, name);
698 if ((p != NULL) && (p->ipo_flags & IPOOL_DELETE))
705 /* ------------------------------------------------------------------------ */
706 /* Function: ipf_pool_select_add_ref */
707 /* Returns: int - 0 = success, else error */
708 /* Parameters: arg(I) - pointer to local context to use */
709 /* unit(I) - ipfilter device to which we are working on */
710 /* name(I) - name of the pool */
712 /* ------------------------------------------------------------------------ */
714 ipf_pool_select_add_ref(arg, unit, name)
721 p = ipf_pool_find(arg, -1, name);
723 p = ipf_pool_find(arg, unit, name);
725 ATOMIC_INC32(p->ipo_ref);
731 /* ------------------------------------------------------------------------ */
732 /* Function: ipf_pool_findeq */
733 /* Returns: int - 0 = success, else error */
734 /* Parameters: softp(I) - pointer to soft context pool information */
735 /* ipo(I) - pointer to the pool getting the new node. */
736 /* addr(I) - pointer to address information to match on */
737 /* mask(I) - pointer to the address mask to match */
739 /* Searches for an exact match of an entry in the pool. */
740 /* ------------------------------------------------------------------------ */
741 extern void printhostmask __P((int, u_32_t *, u_32_t *));
742 static ip_pool_node_t *
743 ipf_pool_findeq(softp, ipo, addr, mask)
744 ipf_pool_softc_t *softp;
746 addrfamily_t *addr, *mask;
750 n = ipo->ipo_head->lookup(ipo->ipo_head, addr, mask);
751 return (ip_pool_node_t *)n;
755 /* ------------------------------------------------------------------------ */
756 /* Function: ipf_pool_search */
757 /* Returns: int - 0 == +ve match, -1 == error, 1 == -ve/no match */
758 /* Parameters: softc(I) - pointer to soft context main structure */
759 /* tptr(I) - pointer to the pool to search */
760 /* version(I) - IP protocol version (4 or 6) */
761 /* dptr(I) - pointer to address information */
762 /* bytes(I) - length of packet */
764 /* Search the pool for a given address and return a search result. */
765 /* ------------------------------------------------------------------------ */
767 ipf_pool_search(softc, tptr, ipversion, dptr, bytes)
768 ipf_main_softc_t *softc;
787 addr = (i6addr_t *)dptr;
788 bzero(&v, sizeof(v));
790 if (ipversion == 4) {
791 v.adf_family = AF_INET;
792 v.adf_len = offsetof(addrfamily_t, adf_addr) +
793 sizeof(struct in_addr);
794 v.adf_addr.in4 = addr->in4;
796 } else if (ipversion == 6) {
797 v.adf_family = AF_INET6;
798 v.adf_len = offsetof(addrfamily_t, adf_addr) +
799 sizeof(struct in6_addr);
800 v.adf_addr.in6 = addr->in6;
805 READ_ENTER(&softc->ipf_poolrw);
807 rn = ipo->ipo_head->matchaddr(ipo->ipo_head, &v);
809 if ((rn != NULL) && (rn->root == 0)) {
810 m = (ip_pool_node_t *)rn;
812 m->ipn_bytes += bytes;
816 RWLOCK_EXIT(&softc->ipf_poolrw);
821 /* ------------------------------------------------------------------------ */
822 /* Function: ipf_pool_insert_node */
823 /* Returns: int - 0 = success, else error */
824 /* Parameters: softc(I) - pointer to soft context main structure */
825 /* softp(I) - pointer to soft context pool information */
826 /* ipo(I) - pointer to the pool getting the new node. */
827 /* node(I) - structure with address/mask to add */
828 /* Locks: WRITE(ipf_poolrw) */
830 /* Add another node to the pool given by ipo. The three parameters passed */
831 /* in (addr, mask, info) shold all be stored in the node. */
832 /* ------------------------------------------------------------------------ */
834 ipf_pool_insert_node(softc, softp, ipo, node)
835 ipf_main_softc_t *softc;
836 ipf_pool_softc_t *softp;
838 struct ip_pool_node *node;
843 if ((node->ipn_addr.adf_len > sizeof(*rn)) ||
844 (node->ipn_addr.adf_len < 4)) {
849 if ((node->ipn_mask.adf_len > sizeof(*rn)) ||
850 (node->ipn_mask.adf_len < 4)) {
855 KMALLOC(x, ip_pool_node_t *);
862 bzero((char *)x->ipn_nodes, sizeof(x->ipn_nodes));
868 x->ipn_pdnext = NULL;
870 if (x->ipn_die != 0) {
872 * If the new node has a given expiration time, insert it
873 * into the list of expiring nodes with the ones to be
874 * removed first added to the front of the list. The
875 * insertion is O(n) but it is kept sorted for quick scans
876 * at expiration interval checks.
880 x->ipn_die = softc->ipf_ticks + IPF_TTLVAL(x->ipn_die);
881 for (n = softp->ipf_node_explist; n != NULL; n = n->ipn_dnext) {
882 if (x->ipn_die < n->ipn_die)
884 if (n->ipn_dnext == NULL) {
886 * We've got to the last node and everything
887 * wanted to be expired before this new node,
888 * so we have to tack it on the end...
891 x->ipn_pdnext = &n->ipn_dnext;
897 if (softp->ipf_node_explist == NULL) {
898 softp->ipf_node_explist = x;
899 x->ipn_pdnext = &softp->ipf_node_explist;
900 } else if (n != NULL) {
902 x->ipn_pdnext = n->ipn_pdnext;
903 n->ipn_pdnext = &x->ipn_dnext;
907 rn = ipo->ipo_head->addaddr(ipo->ipo_head, &x->ipn_addr, &x->ipn_mask,
910 printf("Added %p at %p\n", x, rn);
920 x->ipn_pnext = ipo->ipo_tail;
922 ipo->ipo_tail = &x->ipn_next;
924 softp->ipf_pool_stats.ipls_nodes++;
930 /* ------------------------------------------------------------------------ */
931 /* Function: ipf_pool_create */
932 /* Returns: int - 0 = success, else error */
933 /* Parameters: softc(I) - pointer to soft context main structure */
934 /* softp(I) - pointer to soft context pool information */
935 /* op(I) - pointer to iplookup struct with call details */
936 /* Locks: WRITE(ipf_poolrw) */
938 /* Creates a new group according to the paramters passed in via the */
939 /* iplookupop structure. Does not check to see if the group already exists */
940 /* when being inserted - assume this has already been done. If the pool is */
941 /* marked as being anonymous, give it a new, unique, identifier. Call any */
942 /* other functions required to initialise the structure. */
944 /* If the structure is flagged for deletion then reset the flag and return, */
945 /* as this likely means we've tried to free a pool that is in use (flush) */
946 /* and now want to repopulate it with "new" data. */
947 /* ------------------------------------------------------------------------ */
949 ipf_pool_create(softc, softp, op)
950 ipf_main_softc_t *softc;
951 ipf_pool_softc_t *softp;
954 char name[FR_GROUPLEN];
958 unit = op->iplo_unit;
960 if ((op->iplo_arg & LOOKUP_ANON) == 0) {
961 h = ipf_pool_exists(softp, unit, op->iplo_name);
963 if ((h->ipo_flags & IPOOL_DELETE) == 0) {
967 h->ipo_flags &= ~IPOOL_DELETE;
972 KMALLOC(h, ip_pool_t *);
977 bzero(h, sizeof(*h));
979 if (ipf_rx_inithead(softp->ipf_radix, &h->ipo_head) != 0) {
985 if ((op->iplo_arg & LOOKUP_ANON) != 0) {
988 h->ipo_flags |= IPOOL_ANON;
989 poolnum = LOOKUP_ANON;
991 #if defined(SNPRINTF) && defined(_KERNEL)
992 SNPRINTF(name, sizeof(name), "%x", poolnum);
994 (void)sprintf(name, "%x", poolnum);
997 for (p = softp->ipf_pool_list[unit + 1]; p != NULL; ) {
998 if (strncmp(name, p->ipo_name,
999 sizeof(p->ipo_name)) == 0) {
1001 #if defined(SNPRINTF) && defined(_KERNEL)
1002 SNPRINTF(name, sizeof(name), "%x", poolnum);
1004 (void)sprintf(name, "%x", poolnum);
1006 p = softp->ipf_pool_list[unit + 1];
1011 (void)strncpy(h->ipo_name, name, sizeof(h->ipo_name));
1012 (void)strncpy(op->iplo_name, name, sizeof(op->iplo_name));
1014 (void)strncpy(h->ipo_name, op->iplo_name, sizeof(h->ipo_name));
1017 h->ipo_radix = softp->ipf_radix;
1020 h->ipo_tail = &h->ipo_list;
1022 h->ipo_next = softp->ipf_pool_list[unit + 1];
1023 if (softp->ipf_pool_list[unit + 1] != NULL)
1024 softp->ipf_pool_list[unit + 1]->ipo_pnext = &h->ipo_next;
1025 h->ipo_pnext = &softp->ipf_pool_list[unit + 1];
1026 softp->ipf_pool_list[unit + 1] = h;
1028 softp->ipf_pool_stats.ipls_pools++;
1034 /* ------------------------------------------------------------------------ */
1035 /* Function: ipf_pool_remove_node */
1036 /* Returns: int - 0 = success, else error */
1037 /* Parameters: softc(I) - pointer to soft context main structure */
1038 /* ipo(I) - pointer to the pool to remove the node from. */
1039 /* ipe(I) - address being deleted as a node */
1040 /* Locks: WRITE(ipf_poolrw) */
1042 /* Remove a node from the pool given by ipo. */
1043 /* ------------------------------------------------------------------------ */
1045 ipf_pool_remove_node(softc, softp, ipo, ipe)
1046 ipf_main_softc_t *softc;
1047 ipf_pool_softc_t *softp;
1049 ip_pool_node_t *ipe;
1053 if (ipo->ipo_tail == &ipe->ipn_next)
1054 ipo->ipo_tail = ipe->ipn_pnext;
1056 if (ipe->ipn_pnext != NULL)
1057 *ipe->ipn_pnext = ipe->ipn_next;
1058 if (ipe->ipn_next != NULL)
1059 ipe->ipn_next->ipn_pnext = ipe->ipn_pnext;
1061 if (ipe->ipn_pdnext != NULL)
1062 *ipe->ipn_pdnext = ipe->ipn_dnext;
1063 if (ipe->ipn_dnext != NULL)
1064 ipe->ipn_dnext->ipn_pdnext = ipe->ipn_pdnext;
1066 ptr = ipo->ipo_head->deladdr(ipo->ipo_head, &ipe->ipn_addr,
1070 ipf_pool_node_deref(softp, ipe);
1078 /* ------------------------------------------------------------------------ */
1079 /* Function: ipf_pool_destroy */
1080 /* Returns: int - 0 = success, else error */
1081 /* Parameters: softc(I) - pointer to soft context main structure */
1082 /* softp(I) - pointer to soft context pool information */
1083 /* unit(I) - ipfilter device to which we are working on */
1084 /* name(I) - name of the pool */
1085 /* Locks: WRITE(ipf_poolrw) or WRITE(ipf_global) */
1087 /* Search for a pool using paramters passed in and if it's not otherwise */
1088 /* busy, free it. If it is busy, clear all of its nodes, mark it for being */
1089 /* deleted and return an error saying it is busy. */
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 /* ------------------------------------------------------------------------ */
1096 ipf_pool_destroy(softc, softp, unit, name)
1097 ipf_main_softc_t *softc;
1098 ipf_pool_softc_t *softp;
1104 ipo = ipf_pool_exists(softp, unit, name);
1110 if (ipo->ipo_ref != 1) {
1111 ipf_pool_clearnodes(softc, softp, ipo);
1112 ipo->ipo_flags |= IPOOL_DELETE;
1116 ipf_pool_free(softc, softp, ipo);
1121 /* ------------------------------------------------------------------------ */
1122 /* Function: ipf_pool_flush */
1123 /* Returns: int - number of pools deleted */
1124 /* Parameters: softc(I) - pointer to soft context main structure */
1125 /* arg(I) - pointer to local context to use */
1126 /* fp(I) - which pool(s) to flush */
1127 /* Locks: WRITE(ipf_poolrw) or WRITE(ipf_global) */
1129 /* Free all pools associated with the device that matches the unit number */
1130 /* passed in with operation. */
1132 /* NOTE: Because this function is called out of ipfdetach() where ipf_poolrw*/
1133 /* may not be initialised, we can't use an ASSERT to enforce the locking */
1134 /* assertion that one of the two (ipf_poolrw,ipf_global) is held. */
1135 /* ------------------------------------------------------------------------ */
1137 ipf_pool_flush(softc, arg, fp)
1138 ipf_main_softc_t *softc;
1140 iplookupflush_t *fp;
1142 ipf_pool_softc_t *softp = arg;
1143 int i, num = 0, unit, err;
1146 unit = fp->iplf_unit;
1147 for (i = -1; i <= IPL_LOGMAX; i++) {
1148 if (unit != IPLT_ALL && i != unit)
1150 for (q = softp->ipf_pool_list[i + 1]; (p = q) != NULL; ) {
1152 err = ipf_pool_destroy(softc, softp, i, p->ipo_name);
1161 /* ------------------------------------------------------------------------ */
1162 /* Function: ipf_pool_free */
1164 /* Parameters: softc(I) - pointer to soft context main structure */
1165 /* softp(I) - pointer to soft context pool information */
1166 /* ipo(I) - pointer to pool structure */
1167 /* Locks: WRITE(ipf_poolrw) or WRITE(ipf_global) */
1169 /* Deletes the pool strucutre passed in from the list of pools and deletes */
1170 /* all of the address information stored in it, including any tree data */
1171 /* structures also allocated. */
1173 /* NOTE: Because this function is called out of ipfdetach() where ipf_poolrw*/
1174 /* may not be initialised, we can't use an ASSERT to enforce the locking */
1175 /* assertion that one of the two (ipf_poolrw,ipf_global) is held. */
1176 /* ------------------------------------------------------------------------ */
1178 ipf_pool_free(softc, softp, ipo)
1179 ipf_main_softc_t *softc;
1180 ipf_pool_softc_t *softp;
1184 ipf_pool_clearnodes(softc, softp, ipo);
1186 if (ipo->ipo_next != NULL)
1187 ipo->ipo_next->ipo_pnext = ipo->ipo_pnext;
1188 *ipo->ipo_pnext = ipo->ipo_next;
1189 ipf_rx_freehead(ipo->ipo_head);
1192 softp->ipf_pool_stats.ipls_pools--;
1196 /* ------------------------------------------------------------------------ */
1197 /* Function: ipf_pool_clearnodes */
1199 /* Parameters: softc(I) - pointer to soft context main structure */
1200 /* softp(I) - pointer to soft context pool information */
1201 /* ipo(I) - pointer to pool structure */
1202 /* Locks: WRITE(ipf_poolrw) or WRITE(ipf_global) */
1204 /* Deletes all nodes stored in a pool structure. */
1205 /* ------------------------------------------------------------------------ */
1207 ipf_pool_clearnodes(softc, softp, ipo)
1208 ipf_main_softc_t *softc;
1209 ipf_pool_softc_t *softp;
1212 ip_pool_node_t *n, **next;
1214 for (next = &ipo->ipo_list; (n = *next) != NULL; )
1215 ipf_pool_remove_node(softc, softp, ipo, n);
1217 ipo->ipo_list = NULL;
1221 /* ------------------------------------------------------------------------ */
1222 /* Function: ipf_pool_deref */
1224 /* Parameters: softc(I) - pointer to soft context main structure */
1225 /* arg(I) - pointer to local context to use */
1226 /* pool(I) - pointer to pool structure */
1227 /* Locks: WRITE(ipf_poolrw) */
1229 /* Drop the number of known references to this pool structure by one and if */
1230 /* we arrive at zero known references, free it. */
1231 /* ------------------------------------------------------------------------ */
1233 ipf_pool_deref(softc, arg, pool)
1234 ipf_main_softc_t *softc;
1237 ip_pool_t *ipo = pool;
1241 if (ipo->ipo_ref == 0)
1242 ipf_pool_free(softc, arg, ipo);
1244 else if ((ipo->ipo_ref == 1) && (ipo->ipo_flags & IPOOL_DELETE))
1245 ipf_pool_destroy(softc, arg, ipo->ipo_unit, ipo->ipo_name);
1251 /* ------------------------------------------------------------------------ */
1252 /* Function: ipf_pool_node_deref */
1254 /* Parameters: softp(I) - pointer to soft context pool information */
1255 /* ipn(I) - pointer to pool structure */
1256 /* Locks: WRITE(ipf_poolrw) */
1258 /* Drop a reference to the pool node passed in and if we're the last, free */
1259 /* it all up and adjust the stats accordingly. */
1260 /* ------------------------------------------------------------------------ */
1262 ipf_pool_node_deref(softp, ipn)
1263 ipf_pool_softc_t *softp;
1264 ip_pool_node_t *ipn;
1269 if (ipn->ipn_ref == 0) {
1271 softp->ipf_pool_stats.ipls_nodes--;
1276 /* ------------------------------------------------------------------------ */
1277 /* Function: ipf_pool_iter_next */
1279 /* Parameters: softc(I) - pointer to soft context main structure */
1280 /* arg(I) - pointer to local context to use */
1281 /* token(I) - pointer to pool structure */
1282 /* ilp(IO) - pointer to pool iterating structure */
1284 /* ------------------------------------------------------------------------ */
1286 ipf_pool_iter_next(softc, arg, token, ilp)
1287 ipf_main_softc_t *softc;
1290 ipflookupiter_t *ilp;
1292 ipf_pool_softc_t *softp = arg;
1293 ip_pool_node_t *node, zn, *nextnode;
1294 ip_pool_t *ipo, zp, *nextipo;
1304 READ_ENTER(&softc->ipf_poolrw);
1306 switch (ilp->ili_otype)
1308 case IPFLOOKUPITER_LIST :
1309 ipo = token->ipt_data;
1311 nextipo = softp->ipf_pool_list[(int)ilp->ili_unit + 1];
1313 nextipo = ipo->ipo_next;
1316 if (nextipo != NULL) {
1317 ATOMIC_INC32(nextipo->ipo_ref);
1318 token->ipt_data = nextipo;
1320 bzero((char *)&zp, sizeof(zp));
1322 token->ipt_data = NULL;
1324 pnext = nextipo->ipo_next;
1327 case IPFLOOKUPITER_NODE :
1328 node = token->ipt_data;
1330 ipo = ipf_pool_exists(arg, ilp->ili_unit,
1336 nextnode = ipo->ipo_list;
1340 nextnode = node->ipn_next;
1343 if (nextnode != NULL) {
1344 ATOMIC_INC32(nextnode->ipn_ref);
1345 token->ipt_data = nextnode;
1347 bzero((char *)&zn, sizeof(zn));
1349 token->ipt_data = NULL;
1351 pnext = nextnode->ipn_next;
1361 RWLOCK_EXIT(&softc->ipf_poolrw);
1365 switch (ilp->ili_otype)
1367 case IPFLOOKUPITER_LIST :
1368 err = COPYOUT(nextipo, ilp->ili_data, sizeof(*nextipo));
1374 WRITE_ENTER(&softc->ipf_poolrw);
1375 ipf_pool_deref(softc, softp, ipo);
1376 RWLOCK_EXIT(&softc->ipf_poolrw);
1380 case IPFLOOKUPITER_NODE :
1381 err = COPYOUT(nextnode, ilp->ili_data, sizeof(*nextnode));
1387 WRITE_ENTER(&softc->ipf_poolrw);
1388 ipf_pool_node_deref(softp, node);
1389 RWLOCK_EXIT(&softc->ipf_poolrw);
1394 ipf_token_mark_complete(token);
1400 /* ------------------------------------------------------------------------ */
1401 /* Function: ipf_pool_iterderef */
1403 /* Parameters: softc(I) - pointer to soft context main structure */
1404 /* arg(I) - pointer to local context to use */
1405 /* unit(I) - ipfilter device to which we are working on */
1406 /* Locks: WRITE(ipf_poolrw) */
1408 /* ------------------------------------------------------------------------ */
1410 ipf_pool_iter_deref(softc, arg, otype, unit, data)
1411 ipf_main_softc_t *softc;
1417 ipf_pool_softc_t *softp = arg;
1422 if (unit < 0 || unit > IPL_LOGMAX)
1427 case IPFLOOKUPITER_LIST :
1428 ipf_pool_deref(softc, softp, (ip_pool_t *)data);
1431 case IPFLOOKUPITER_NODE :
1432 ipf_pool_node_deref(softp, (ip_pool_node_t *)data);
1442 /* ------------------------------------------------------------------------ */
1443 /* Function: ipf_pool_expire */
1445 /* Parameters: softc(I) - pointer to soft context main structure */
1446 /* arg(I) - pointer to local context to use */
1448 /* At present this function exists just to support temporary addition of */
1449 /* nodes to the address pool. */
1450 /* ------------------------------------------------------------------------ */
1452 ipf_pool_expire(softc, arg)
1453 ipf_main_softc_t *softc;
1456 ipf_pool_softc_t *softp = arg;
1459 while ((n = softp->ipf_node_explist) != NULL) {
1461 * Because the list is kept sorted on insertion, the fist
1462 * one that dies in the future means no more work to do.
1464 if (n->ipn_die > softc->ipf_ticks)
1466 ipf_pool_remove_node(softc, softp, n->ipn_owner, n);
1475 ipf_pool_dump(softc, arg)
1476 ipf_main_softc_t *softc;
1479 ipf_pool_softc_t *softp = arg;
1483 printf("List of configured pools\n");
1484 for (i = 0; i <= LOOKUP_POOL_MAX; i++)
1485 for (ipl = softp->ipf_pool_list[i]; ipl != NULL;
1486 ipl = ipl->ipo_next)
1487 printpool(ipl, bcopywrap, NULL, opts, NULL);