4 * Copyright (C) 2012 by Darren Reed.
6 * See the IPFILTER.LICENCE file for details on licencing.
8 #if defined(KERNEL) || defined(_KERNEL)
14 #include <sys/param.h>
15 #include <sys/types.h>
16 #include <sys/errno.h>
29 #include <sys/socket.h>
30 #if defined(__FreeBSD_version) && (__FreeBSD_version >= 300000)
31 # include <sys/malloc.h>
33 #if defined(__FreeBSD__)
34 # include <sys/cdefs.h>
35 # include <sys/proc.h>
37 #if !defined(__svr4__) && !defined(__SVR4) && !defined(__hpux) && \
39 # include <sys/mbuf.h>
42 # include <sys/systm.h>
46 #include <netinet/in.h>
49 #include "netinet/ip_compat.h"
50 #include "netinet/ip_fil.h"
51 #include "netinet/ip_lookup.h"
52 #include "netinet/ip_htable.h"
56 static const char rcsid[] = "@(#)$Id$";
60 static iphtent_t *ipf_iphmfind6 __P((iphtable_t *, i6addr_t *));
62 static iphtent_t *ipf_iphmfind __P((iphtable_t *, struct in_addr *));
63 static int ipf_iphmfindip __P((ipf_main_softc_t *, void *, int, void *, u_int));
64 static int ipf_htable_clear __P((ipf_main_softc_t *, void *, iphtable_t *));
65 static int ipf_htable_create __P((ipf_main_softc_t *, void *, iplookupop_t *));
66 static int ipf_htable_deref __P((ipf_main_softc_t *, void *, void *));
67 static int ipf_htable_destroy __P((ipf_main_softc_t *, void *, int, char *));
68 static void *ipf_htable_exists __P((void *, int, char *));
69 static size_t ipf_htable_flush __P((ipf_main_softc_t *, void *,
71 static void ipf_htable_free __P((void *, iphtable_t *));
72 static int ipf_htable_iter_deref __P((ipf_main_softc_t *, void *, int,
74 static int ipf_htable_iter_next __P((ipf_main_softc_t *, void *, ipftoken_t *,
76 static int ipf_htable_node_add __P((ipf_main_softc_t *, void *,
77 iplookupop_t *, int));
78 static int ipf_htable_node_del __P((ipf_main_softc_t *, void *,
79 iplookupop_t *, int));
80 static int ipf_htable_remove __P((ipf_main_softc_t *, void *, iphtable_t *));
81 static void *ipf_htable_soft_create __P((ipf_main_softc_t *));
82 static void ipf_htable_soft_destroy __P((ipf_main_softc_t *, void *));
83 static int ipf_htable_soft_init __P((ipf_main_softc_t *, void *));
84 static void ipf_htable_soft_fini __P((ipf_main_softc_t *, void *));
85 static int ipf_htable_stats_get __P((ipf_main_softc_t *, void *,
87 static int ipf_htable_table_add __P((ipf_main_softc_t *, void *,
89 static int ipf_htable_table_del __P((ipf_main_softc_t *, void *,
91 static int ipf_htent_deref __P((void *, iphtent_t *));
92 static iphtent_t *ipf_htent_find __P((iphtable_t *, iphtent_t *));
93 static int ipf_htent_insert __P((ipf_main_softc_t *, void *, iphtable_t *,
95 static int ipf_htent_remove __P((ipf_main_softc_t *, void *, iphtable_t *,
97 static void *ipf_htable_select_add_ref __P((void *, int, char *));
98 static void ipf_htable_expire __P((ipf_main_softc_t *, void *));
101 typedef struct ipf_htable_softc_s {
102 u_long ipht_nomem[LOOKUP_POOL_SZ];
103 u_long ipf_nhtables[LOOKUP_POOL_SZ];
104 u_long ipf_nhtnodes[LOOKUP_POOL_SZ];
105 iphtable_t *ipf_htables[LOOKUP_POOL_SZ];
106 iphtent_t *ipf_node_explist;
107 } ipf_htable_softc_t;
109 ipf_lookup_t ipf_htable_backend = {
111 ipf_htable_soft_create,
112 ipf_htable_soft_destroy,
113 ipf_htable_soft_init,
114 ipf_htable_soft_fini,
117 ipf_htable_iter_deref,
118 ipf_htable_iter_next,
121 ipf_htable_stats_get,
122 ipf_htable_table_add,
123 ipf_htable_table_del,
126 ipf_htable_select_add_ref,
133 /* ------------------------------------------------------------------------ */
134 /* Function: ipf_htable_soft_create */
135 /* Returns: void * - NULL = failure, else pointer to local context */
136 /* Parameters: softc(I) - pointer to soft context main structure */
138 /* Initialise the routing table data structures where required. */
139 /* ------------------------------------------------------------------------ */
141 ipf_htable_soft_create(softc)
142 ipf_main_softc_t *softc;
144 ipf_htable_softc_t *softh;
146 KMALLOC(softh, ipf_htable_softc_t *);
152 bzero((char *)softh, sizeof(*softh));
158 /* ------------------------------------------------------------------------ */
159 /* Function: ipf_htable_soft_destroy */
161 /* Parameters: softc(I) - pointer to soft context main structure */
162 /* arg(I) - pointer to local context to use */
164 /* Clean up the pool by free'ing the radix tree associated with it and free */
165 /* up the pool context too. */
166 /* ------------------------------------------------------------------------ */
168 ipf_htable_soft_destroy(softc, arg)
169 ipf_main_softc_t *softc;
172 ipf_htable_softc_t *softh = arg;
178 /* ------------------------------------------------------------------------ */
179 /* Function: ipf_htable_soft_init */
180 /* Returns: int - 0 = success, else error */
181 /* Parameters: softc(I) - pointer to soft context main structure */
182 /* arg(I) - pointer to local context to use */
184 /* Initialise the hash table ready for use. */
185 /* ------------------------------------------------------------------------ */
187 ipf_htable_soft_init(softc, arg)
188 ipf_main_softc_t *softc;
191 ipf_htable_softc_t *softh = arg;
193 bzero((char *)softh, sizeof(*softh));
199 /* ------------------------------------------------------------------------ */
200 /* Function: ipf_htable_soft_fini */
202 /* Parameters: softc(I) - pointer to soft context main structure */
203 /* arg(I) - pointer to local context to use */
204 /* Locks: WRITE(ipf_global) */
206 /* Clean up all the pool data structures allocated and call the cleanup */
207 /* function for the radix tree that supports the pools. ipf_pool_destroy is */
208 /* used to delete the pools one by one to ensure they're properly freed up. */
209 /* ------------------------------------------------------------------------ */
211 ipf_htable_soft_fini(softc, arg)
212 ipf_main_softc_t *softc;
217 fop.iplf_type = IPLT_HASH;
218 fop.iplf_unit = IPL_LOGALL;
221 *fop.iplf_name = '\0';
222 ipf_htable_flush(softc, arg, &fop);
226 /* ------------------------------------------------------------------------ */
227 /* Function: ipf_htable_stats_get */
228 /* Returns: int - 0 = success, else error */
229 /* Parameters: softc(I) - pointer to soft context main structure */
230 /* arg(I) - pointer to local context to use */
231 /* op(I) - pointer to lookup operation data */
233 /* Copy the relevant statistics out of internal structures and into the */
234 /* structure used to export statistics. */
235 /* ------------------------------------------------------------------------ */
237 ipf_htable_stats_get(softc, arg, op)
238 ipf_main_softc_t *softc;
242 ipf_htable_softc_t *softh = arg;
246 if (op->iplo_size != sizeof(stats)) {
251 stats.iphs_tables = softh->ipf_htables[op->iplo_unit + 1];
252 stats.iphs_numtables = softh->ipf_nhtables[op->iplo_unit + 1];
253 stats.iphs_numnodes = softh->ipf_nhtnodes[op->iplo_unit + 1];
254 stats.iphs_nomem = softh->ipht_nomem[op->iplo_unit + 1];
256 err = COPYOUT(&stats, op->iplo_struct, sizeof(stats));
266 /* ------------------------------------------------------------------------ */
267 /* Function: ipf_htable_create */
268 /* Returns: int - 0 = success, else error */
269 /* Parameters: softc(I) - pointer to soft context main structure */
270 /* arg(I) - pointer to local context to use */
271 /* op(I) - pointer to lookup operation data */
273 /* Create a new hash table using the template passed. */
274 /* ------------------------------------------------------------------------ */
276 ipf_htable_create(softc, arg, op)
277 ipf_main_softc_t *softc;
281 ipf_htable_softc_t *softh = arg;
282 iphtable_t htab, *iph, *oiph;
283 char name[FR_GROUPLEN];
286 if (op->iplo_size != sizeof(htab)) {
290 err = COPYIN(op->iplo_struct, &htab, sizeof(htab));
296 unit = op->iplo_unit;
297 if (htab.iph_unit != unit) {
301 if (htab.iph_size < 1) {
307 if ((op->iplo_arg & IPHASH_ANON) == 0) {
308 iph = ipf_htable_exists(softh, unit, op->iplo_name);
310 if ((iph->iph_flags & IPHASH_DELETE) == 0) {
314 iph->iph_flags &= ~IPHASH_DELETE;
320 KMALLOC(iph, iphtable_t *);
322 softh->ipht_nomem[op->iplo_unit + 1]++;
328 if ((op->iplo_arg & IPHASH_ANON) != 0) {
332 #if defined(SNPRINTF) && defined(_KERNEL)
333 SNPRINTF(name, sizeof(name), "%u", i);
335 (void)sprintf(name, "%u", i);
337 for (oiph = softh->ipf_htables[unit + 1]; oiph != NULL;
338 oiph = oiph->iph_next)
339 if (strncmp(oiph->iph_name, name,
340 sizeof(oiph->iph_name)) == 0)
342 } while (oiph != NULL);
344 (void)strncpy(iph->iph_name, name, sizeof(iph->iph_name));
345 (void)strncpy(op->iplo_name, name, sizeof(op->iplo_name));
346 iph->iph_type |= IPHASH_ANON;
348 (void)strncpy(iph->iph_name, op->iplo_name,
349 sizeof(iph->iph_name));
350 iph->iph_name[sizeof(iph->iph_name) - 1] = '\0';
353 KMALLOCS(iph->iph_table, iphtent_t **,
354 iph->iph_size * sizeof(*iph->iph_table));
355 if (iph->iph_table == NULL) {
357 softh->ipht_nomem[unit + 1]++;
362 bzero((char *)iph->iph_table, iph->iph_size * sizeof(*iph->iph_table));
363 iph->iph_maskset[0] = 0;
364 iph->iph_maskset[1] = 0;
365 iph->iph_maskset[2] = 0;
366 iph->iph_maskset[3] = 0;
369 iph->iph_list = NULL;
370 iph->iph_tail = &iph->iph_list;
371 iph->iph_next = softh->ipf_htables[unit + 1];
372 iph->iph_pnext = &softh->ipf_htables[unit + 1];
373 if (softh->ipf_htables[unit + 1] != NULL)
374 softh->ipf_htables[unit + 1]->iph_pnext = &iph->iph_next;
375 softh->ipf_htables[unit + 1] = iph;
377 softh->ipf_nhtables[unit + 1]++;
383 /* ------------------------------------------------------------------------ */
384 /* Function: ipf_htable_table_del */
385 /* Returns: int - 0 = success, else error */
386 /* Parameters: softc(I) - pointer to soft context main structure */
387 /* arg(I) - pointer to local context to use */
388 /* op(I) - pointer to lookup operation data */
390 /* ------------------------------------------------------------------------ */
392 ipf_htable_table_del(softc, arg, op)
393 ipf_main_softc_t *softc;
397 return ipf_htable_destroy(softc, arg, op->iplo_unit, op->iplo_name);
401 /* ------------------------------------------------------------------------ */
402 /* Function: ipf_htable_destroy */
403 /* Returns: int - 0 = success, else error */
404 /* Parameters: softc(I) - pointer to soft context main structure */
405 /* arg(I) - pointer to local context to use */
406 /* op(I) - pointer to lookup operation data */
408 /* Find the hash table that belongs to the relevant part of ipfilter with a */
409 /* matching name and attempt to destroy it. If it is in use, empty it out */
410 /* and mark it for deletion so that when all the references disappear, it */
411 /* can be removed. */
412 /* ------------------------------------------------------------------------ */
414 ipf_htable_destroy(softc, arg, unit, name)
415 ipf_main_softc_t *softc;
422 iph = ipf_htable_find(arg, unit, name);
428 if (iph->iph_unit != unit) {
433 if (iph->iph_ref != 0) {
434 ipf_htable_clear(softc, arg, iph);
435 iph->iph_flags |= IPHASH_DELETE;
439 ipf_htable_remove(softc, arg, iph);
445 /* ------------------------------------------------------------------------ */
446 /* Function: ipf_htable_clear */
447 /* Returns: int - 0 = success, else error */
448 /* Parameters: softc(I) - pointer to soft context main structure */
449 /* arg(I) - pointer to local context to use */
450 /* iph(I) - pointer to hash table to destroy */
452 /* Clean out the hash table by walking the list of entries and removing */
453 /* each one, one by one. */
454 /* ------------------------------------------------------------------------ */
456 ipf_htable_clear(softc, arg, iph)
457 ipf_main_softc_t *softc;
463 while ((ipe = iph->iph_list) != NULL)
464 if (ipf_htent_remove(softc, arg, iph, ipe) != 0)
470 /* ------------------------------------------------------------------------ */
471 /* Function: ipf_htable_free */
473 /* Parameters: arg(I) - pointer to local context to use */
474 /* iph(I) - pointer to hash table to destroy */
476 /* ------------------------------------------------------------------------ */
478 ipf_htable_free(arg, iph)
482 ipf_htable_softc_t *softh = arg;
484 if (iph->iph_next != NULL)
485 iph->iph_next->iph_pnext = iph->iph_pnext;
486 if (iph->iph_pnext != NULL)
487 *iph->iph_pnext = iph->iph_next;
488 iph->iph_pnext = NULL;
489 iph->iph_next = NULL;
491 softh->ipf_nhtables[iph->iph_unit + 1]--;
493 KFREES(iph->iph_table, iph->iph_size * sizeof(*iph->iph_table));
498 /* ------------------------------------------------------------------------ */
499 /* Function: ipf_htable_remove */
500 /* Returns: int - 0 = success, else error */
501 /* Parameters: softc(I) - pointer to soft context main structure */
502 /* arg(I) - pointer to local context to use */
503 /* iph(I) - pointer to hash table to destroy */
505 /* It is necessary to unlink here as well as free (called by deref) so that */
506 /* the while loop in ipf_htable_flush() functions properly. */
507 /* ------------------------------------------------------------------------ */
509 ipf_htable_remove(softc, arg, iph)
510 ipf_main_softc_t *softc;
515 if (ipf_htable_clear(softc, arg, iph) != 0)
518 if (iph->iph_pnext != NULL)
519 *iph->iph_pnext = iph->iph_next;
520 if (iph->iph_next != NULL)
521 iph->iph_next->iph_pnext = iph->iph_pnext;
522 iph->iph_pnext = NULL;
523 iph->iph_next = NULL;
525 return ipf_htable_deref(softc, arg, iph);
529 /* ------------------------------------------------------------------------ */
530 /* Function: ipf_htable_node_del */
531 /* Returns: int - 0 = success, else error */
532 /* Parameters: softc(I) - pointer to soft context main structure */
533 /* arg(I) - pointer to local context to use */
534 /* op(I) - pointer to lookup operation data */
535 /* uid(I) - real uid of process doing operation */
537 /* ------------------------------------------------------------------------ */
539 ipf_htable_node_del(softc, arg, op, uid)
540 ipf_main_softc_t *softc;
549 if (op->iplo_size != sizeof(hte)) {
554 err = COPYIN(op->iplo_struct, &hte, sizeof(hte));
560 iph = ipf_htable_find(arg, op->iplo_unit, op->iplo_name);
566 ent = ipf_htent_find(iph, &hte);
572 if ((uid != 0) && (ent->ipe_uid != uid)) {
577 err = ipf_htent_remove(softc, arg, iph, ent);
583 /* ------------------------------------------------------------------------ */
584 /* Function: ipf_htable_node_del */
585 /* Returns: int - 0 = success, else error */
586 /* Parameters: softc(I) - pointer to soft context main structure */
587 /* arg(I) - pointer to local context to use */
588 /* op(I) - pointer to lookup operation data */
590 /* ------------------------------------------------------------------------ */
592 ipf_htable_table_add(softc, arg, op)
593 ipf_main_softc_t *softc;
599 if (ipf_htable_find(arg, op->iplo_unit, op->iplo_name) != NULL) {
603 err = ipf_htable_create(softc, arg, op);
610 /* ------------------------------------------------------------------------ */
611 /* Function: ipf_htent_remove */
612 /* Returns: int - 0 = success, else error */
613 /* Parameters: softc(I) - pointer to soft context main structure */
614 /* arg(I) - pointer to local context to use */
615 /* iph(I) - pointer to hash table */
616 /* ipe(I) - pointer to hash table entry to remove */
618 /* Delete an entry from a hash table. */
619 /* ------------------------------------------------------------------------ */
621 ipf_htent_remove(softc, arg, iph, ipe)
622 ipf_main_softc_t *softc;
628 if (iph->iph_tail == &ipe->ipe_next)
629 iph->iph_tail = ipe->ipe_pnext;
631 if (ipe->ipe_hnext != NULL)
632 ipe->ipe_hnext->ipe_phnext = ipe->ipe_phnext;
633 if (ipe->ipe_phnext != NULL)
634 *ipe->ipe_phnext = ipe->ipe_hnext;
635 ipe->ipe_phnext = NULL;
636 ipe->ipe_hnext = NULL;
638 if (ipe->ipe_dnext != NULL)
639 ipe->ipe_dnext->ipe_pdnext = ipe->ipe_pdnext;
640 if (ipe->ipe_pdnext != NULL)
641 *ipe->ipe_pdnext = ipe->ipe_dnext;
642 ipe->ipe_pdnext = NULL;
643 ipe->ipe_dnext = NULL;
645 if (ipe->ipe_next != NULL)
646 ipe->ipe_next->ipe_pnext = ipe->ipe_pnext;
647 if (ipe->ipe_pnext != NULL)
648 *ipe->ipe_pnext = ipe->ipe_next;
649 ipe->ipe_pnext = NULL;
650 ipe->ipe_next = NULL;
652 switch (iph->iph_type & ~IPHASH_ANON)
654 case IPHASH_GROUPMAP :
655 if (ipe->ipe_group != NULL)
656 ipf_group_del(softc, ipe->ipe_ptr, NULL);
665 return ipf_htent_deref(arg, ipe);
669 /* ------------------------------------------------------------------------ */
670 /* Function: ipf_htable_deref */
671 /* Returns: int - 0 = success, else error */
672 /* Parameters: softc(I) - pointer to soft context main structure */
673 /* arg(I) - pointer to local context to use */
674 /* object(I) - pointer to hash table */
676 /* ------------------------------------------------------------------------ */
678 ipf_htable_deref(softc, arg, object)
679 ipf_main_softc_t *softc;
682 ipf_htable_softc_t *softh = arg;
683 iphtable_t *iph = object;
689 if (iph->iph_ref == 0) {
690 ipf_htable_free(softh, iph);
697 /* ------------------------------------------------------------------------ */
698 /* Function: ipf_htent_deref */
699 /* Parameters: arg(I) - pointer to local context to use */
702 /* ------------------------------------------------------------------------ */
704 ipf_htent_deref(arg, ipe)
708 ipf_htable_softc_t *softh = arg;
711 if (ipe->ipe_ref == 0) {
712 softh->ipf_nhtnodes[ipe->ipe_unit + 1]--;
722 /* ------------------------------------------------------------------------ */
723 /* Function: ipf_htable_exists */
724 /* Parameters: arg(I) - pointer to local context to use */
726 /* ------------------------------------------------------------------------ */
728 ipf_htable_exists(arg, unit, name)
733 ipf_htable_softc_t *softh = arg;
736 if (unit == IPL_LOGALL) {
739 for (i = 0; i <= LOOKUP_POOL_MAX; i++) {
740 for (iph = softh->ipf_htables[i]; iph != NULL;
741 iph = iph->iph_next) {
742 if (strncmp(iph->iph_name, name,
743 sizeof(iph->iph_name)) == 0)
750 for (iph = softh->ipf_htables[unit + 1]; iph != NULL;
751 iph = iph->iph_next) {
752 if (strncmp(iph->iph_name, name,
753 sizeof(iph->iph_name)) == 0)
761 /* ------------------------------------------------------------------------ */
762 /* Function: ipf_htable_select_add_ref */
763 /* Returns: void * - NULL = failure, else pointer to the hash table */
764 /* Parameters: arg(I) - pointer to local context to use */
765 /* unit(I) - ipfilter device to which we are working on */
766 /* name(I) - name of the hash table */
768 /* ------------------------------------------------------------------------ */
770 ipf_htable_select_add_ref(arg, unit, name)
777 iph = ipf_htable_exists(arg, unit, name);
779 ATOMIC_INC32(iph->iph_ref);
785 /* ------------------------------------------------------------------------ */
786 /* Function: ipf_htable_find */
787 /* Returns: void * - NULL = failure, else pointer to the hash table */
788 /* Parameters: arg(I) - pointer to local context to use */
789 /* unit(I) - ipfilter device to which we are working on */
790 /* name(I) - name of the hash table */
792 /* This function is exposed becaues it is used in the group-map feature. */
793 /* ------------------------------------------------------------------------ */
795 ipf_htable_find(arg, unit, name)
802 iph = ipf_htable_exists(arg, unit, name);
803 if ((iph != NULL) && (iph->iph_flags & IPHASH_DELETE) == 0)
810 /* ------------------------------------------------------------------------ */
811 /* Function: ipf_htable_flush */
812 /* Returns: size_t - number of entries flushed */
813 /* Parameters: softc(I) - pointer to soft context main structure */
814 /* arg(I) - pointer to local context to use */
815 /* op(I) - pointer to lookup operation data */
817 /* ------------------------------------------------------------------------ */
819 ipf_htable_flush(softc, arg, op)
820 ipf_main_softc_t *softc;
824 ipf_htable_softc_t *softh = arg;
831 for (i = -1; i <= IPL_LOGMAX; i++) {
832 if (op->iplf_unit == i || op->iplf_unit == IPL_LOGALL) {
833 while ((iph = softh->ipf_htables[i + 1]) != NULL) {
834 if (ipf_htable_remove(softc, arg, iph) == 0) {
837 iph->iph_flags |= IPHASH_DELETE;
847 /* ------------------------------------------------------------------------ */
848 /* Function: ipf_htable_node_add */
849 /* Returns: int - 0 = success, else error */
850 /* Parameters: softc(I) - pointer to soft context main structure */
851 /* arg(I) - pointer to local context to use */
852 /* op(I) - pointer to lookup operation data */
853 /* uid(I) - real uid of process doing operation */
855 /* ------------------------------------------------------------------------ */
857 ipf_htable_node_add(softc, arg, op, uid)
858 ipf_main_softc_t *softc;
867 if (op->iplo_size != sizeof(hte)) {
872 err = COPYIN(op->iplo_struct, &hte, sizeof(hte));
879 iph = ipf_htable_find(arg, op->iplo_unit, op->iplo_name);
885 if (ipf_htent_find(iph, &hte) != NULL) {
890 err = ipf_htent_insert(softc, arg, iph, &hte);
896 /* ------------------------------------------------------------------------ */
897 /* Function: ipf_htent_insert */
898 /* Returns: int - 0 = success, -1 = error */
899 /* Parameters: softc(I) - pointer to soft context main structure */
900 /* arg(I) - pointer to local context to use */
901 /* op(I) - pointer to lookup operation data */
904 /* Add an entry to a hash table. */
905 /* ------------------------------------------------------------------------ */
907 ipf_htent_insert(softc, arg, iph, ipeo)
908 ipf_main_softc_t *softc;
913 ipf_htable_softc_t *softh = arg;
918 KMALLOC(ipe, iphtent_t *);
922 bcopy((char *)ipeo, (char *)ipe, sizeof(*ipe));
923 ipe->ipe_addr.i6[0] &= ipe->ipe_mask.i6[0];
924 if (ipe->ipe_family == AF_INET) {
925 bits = count4bits(ipe->ipe_mask.in4_addr);
926 ipe->ipe_addr.i6[1] = 0;
927 ipe->ipe_addr.i6[2] = 0;
928 ipe->ipe_addr.i6[3] = 0;
929 ipe->ipe_mask.i6[1] = 0;
930 ipe->ipe_mask.i6[2] = 0;
931 ipe->ipe_mask.i6[3] = 0;
932 hv = IPE_V4_HASH_FN(ipe->ipe_addr.in4_addr,
933 ipe->ipe_mask.in4_addr, iph->iph_size);
936 if (ipe->ipe_family == AF_INET6) {
937 ipe->ipe_addr.i6[1] &= ipe->ipe_mask.i6[1];
938 ipe->ipe_addr.i6[2] &= ipe->ipe_mask.i6[2];
939 ipe->ipe_addr.i6[3] &= ipe->ipe_mask.i6[3];
941 bits = count6bits(ipe->ipe_mask.i6);
942 hv = IPE_V6_HASH_FN(ipe->ipe_addr.i6,
943 ipe->ipe_mask.i6, iph->iph_size);
951 ipe->ipe_owner = iph;
953 ipe->ipe_hnext = iph->iph_table[hv];
954 ipe->ipe_phnext = iph->iph_table + hv;
956 if (iph->iph_table[hv] != NULL)
957 iph->iph_table[hv]->ipe_phnext = &ipe->ipe_hnext;
958 iph->iph_table[hv] = ipe;
960 ipe->ipe_pnext = iph->iph_tail;
961 *iph->iph_tail = ipe;
962 iph->iph_tail = &ipe->ipe_next;
963 ipe->ipe_next = NULL;
965 if (ipe->ipe_die != 0) {
967 * If the new node has a given expiration time, insert it
968 * into the list of expiring nodes with the ones to be
969 * removed first added to the front of the list. The
970 * insertion is O(n) but it is kept sorted for quick scans
971 * at expiration interval checks.
975 ipe->ipe_die = softc->ipf_ticks + IPF_TTLVAL(ipe->ipe_die);
976 for (n = softh->ipf_node_explist; n != NULL; n = n->ipe_dnext) {
977 if (ipe->ipe_die < n->ipe_die)
979 if (n->ipe_dnext == NULL) {
981 * We've got to the last node and everything
982 * wanted to be expired before this new node,
983 * so we have to tack it on the end...
986 ipe->ipe_pdnext = &n->ipe_dnext;
992 if (softh->ipf_node_explist == NULL) {
993 softh->ipf_node_explist = ipe;
994 ipe->ipe_pdnext = &softh->ipf_node_explist;
995 } else if (n != NULL) {
997 ipe->ipe_pdnext = n->ipe_pdnext;
998 n->ipe_pdnext = &ipe->ipe_dnext;
1002 if (ipe->ipe_family == AF_INET) {
1003 ipf_inet_mask_add(bits, &iph->iph_v4_masks);
1006 else if (ipe->ipe_family == AF_INET6) {
1007 ipf_inet6_mask_add(bits, &ipe->ipe_mask, &iph->iph_v6_masks);
1011 switch (iph->iph_type & ~IPHASH_ANON)
1013 case IPHASH_GROUPMAP :
1014 ipe->ipe_ptr = ipf_group_add(softc, ipe->ipe_group, NULL,
1015 iph->iph_flags, IPL_LOGIPF,
1020 ipe->ipe_ptr = NULL;
1025 ipe->ipe_unit = iph->iph_unit;
1026 softh->ipf_nhtnodes[ipe->ipe_unit + 1]++;
1032 /* ------------------------------------------------------------------------ */
1033 /* Function: ipf_htent_find */
1034 /* Returns: int - 0 = success, else error */
1035 /* Parameters: iph(I) - pointer to table to search */
1036 /* ipeo(I) - pointer to entry to find */
1038 /* While it isn't absolutely necessary to for the address and mask to be */
1039 /* passed in through an iphtent_t structure, one is always present when it */
1040 /* is time to call this function, so it is just more convenient. */
1041 /* ------------------------------------------------------------------------ */
1043 ipf_htent_find(iph, ipeo)
1047 iphtent_t ipe, *ent;
1051 bcopy((char *)ipeo, (char *)&ipe, sizeof(ipe));
1052 ipe.ipe_addr.i6[0] &= ipe.ipe_mask.i6[0];
1053 ipe.ipe_addr.i6[1] &= ipe.ipe_mask.i6[1];
1054 ipe.ipe_addr.i6[2] &= ipe.ipe_mask.i6[2];
1055 ipe.ipe_addr.i6[3] &= ipe.ipe_mask.i6[3];
1056 if (ipe.ipe_family == AF_INET) {
1057 bits = count4bits(ipe.ipe_mask.in4_addr);
1058 ipe.ipe_addr.i6[1] = 0;
1059 ipe.ipe_addr.i6[2] = 0;
1060 ipe.ipe_addr.i6[3] = 0;
1061 ipe.ipe_mask.i6[1] = 0;
1062 ipe.ipe_mask.i6[2] = 0;
1063 ipe.ipe_mask.i6[3] = 0;
1064 hv = IPE_V4_HASH_FN(ipe.ipe_addr.in4_addr,
1065 ipe.ipe_mask.in4_addr, iph->iph_size);
1068 if (ipe.ipe_family == AF_INET6) {
1069 bits = count6bits(ipe.ipe_mask.i6);
1070 hv = IPE_V6_HASH_FN(ipe.ipe_addr.i6,
1071 ipe.ipe_mask.i6, iph->iph_size);
1076 for (ent = iph->iph_table[hv]; ent != NULL; ent = ent->ipe_hnext) {
1077 if (ent->ipe_family != ipe.ipe_family)
1079 if (IP6_NEQ(&ipe.ipe_addr, &ent->ipe_addr))
1081 if (IP6_NEQ(&ipe.ipe_mask, &ent->ipe_mask))
1090 /* ------------------------------------------------------------------------ */
1091 /* Function: ipf_iphmfindgroup */
1092 /* Returns: int - 0 = success, else error */
1093 /* Parameters: softc(I) - pointer to soft context main structure */
1097 /* Search a hash table for a matching entry and return the pointer stored */
1098 /* in it for use as the next group of rules to search. */
1100 /* This function is exposed becaues it is used in the group-map feature. */
1101 /* ------------------------------------------------------------------------ */
1103 ipf_iphmfindgroup(softc, tptr, aptr)
1104 ipf_main_softc_t *softc;
1107 struct in_addr *addr;
1112 READ_ENTER(&softc->ipf_poolrw);
1116 ipe = ipf_iphmfind(iph, addr);
1118 rval = ipe->ipe_ptr;
1121 RWLOCK_EXIT(&softc->ipf_poolrw);
1126 /* ------------------------------------------------------------------------ */
1127 /* Function: ipf_iphmfindip */
1128 /* Returns: int - 0 == +ve match, -1 == error, 1 == -ve/no match */
1129 /* Parameters: softc(I) - pointer to soft context main structure */
1130 /* tptr(I) - pointer to the pool to search */
1131 /* ipversion(I) - IP protocol version (4 or 6) */
1132 /* aptr(I) - pointer to address information */
1133 /* bytes(I) - packet length */
1135 /* Search the hash table for a given address and return a search result. */
1136 /* ------------------------------------------------------------------------ */
1138 ipf_iphmfindip(softc, tptr, ipversion, aptr, bytes)
1139 ipf_main_softc_t *softc;
1144 struct in_addr *addr;
1149 if (tptr == NULL || aptr == NULL)
1155 READ_ENTER(&softc->ipf_poolrw);
1156 if (ipversion == 4) {
1157 ipe = ipf_iphmfind(iph, addr);
1159 } else if (ipversion == 6) {
1160 ipe = ipf_iphmfind6(iph, (i6addr_t *)addr);
1169 ipe->ipe_bytes += bytes;
1173 RWLOCK_EXIT(&softc->ipf_poolrw);
1178 /* ------------------------------------------------------------------------ */
1179 /* Function: ipf_iphmfindip */
1180 /* Parameters: iph(I) - pointer to hash table */
1181 /* addr(I) - pointer to IPv4 address */
1182 /* Locks: ipf_poolrw */
1184 /* ------------------------------------------------------------------------ */
1186 ipf_iphmfind(iph, addr)
1188 struct in_addr *addr;
1197 msk = iph->iph_v4_masks.imt4_active[i];
1198 ips = addr->s_addr & msk;
1199 hv = IPE_V4_HASH_FN(ips, msk, iph->iph_size);
1200 for (ipe = iph->iph_table[hv]; (ipe != NULL); ipe = ipe->ipe_hnext) {
1201 if ((ipe->ipe_family != AF_INET) ||
1202 (ipe->ipe_mask.in4_addr != msk) ||
1203 (ipe->ipe_addr.in4_addr != ips)) {
1211 if (i < iph->iph_v4_masks.imt4_max)
1218 /* ------------------------------------------------------------------------ */
1219 /* Function: ipf_htable_iter_next */
1220 /* Returns: int - 0 = success, else error */
1221 /* Parameters: softc(I) - pointer to soft context main structure */
1222 /* arg(I) - pointer to local context to use */
1226 /* ------------------------------------------------------------------------ */
1228 ipf_htable_iter_next(softc, arg, token, ilp)
1229 ipf_main_softc_t *softc;
1232 ipflookupiter_t *ilp;
1234 ipf_htable_softc_t *softh = arg;
1235 iphtent_t *node, zn, *nextnode;
1236 iphtable_t *iph, zp, *nextiph;
1246 READ_ENTER(&softc->ipf_poolrw);
1248 switch (ilp->ili_otype)
1250 case IPFLOOKUPITER_LIST :
1251 iph = token->ipt_data;
1253 nextiph = softh->ipf_htables[(int)ilp->ili_unit + 1];
1255 nextiph = iph->iph_next;
1258 if (nextiph != NULL) {
1259 ATOMIC_INC(nextiph->iph_ref);
1260 token->ipt_data = nextiph;
1262 bzero((char *)&zp, sizeof(zp));
1264 token->ipt_data = NULL;
1266 hnext = nextiph->iph_next;
1269 case IPFLOOKUPITER_NODE :
1270 node = token->ipt_data;
1272 iph = ipf_htable_find(arg, ilp->ili_unit,
1278 nextnode = iph->iph_list;
1281 nextnode = node->ipe_next;
1284 if (nextnode != NULL) {
1285 ATOMIC_INC(nextnode->ipe_ref);
1286 token->ipt_data = nextnode;
1288 bzero((char *)&zn, sizeof(zn));
1290 token->ipt_data = NULL;
1292 hnext = nextnode->ipe_next;
1302 RWLOCK_EXIT(&softc->ipf_poolrw);
1306 switch (ilp->ili_otype)
1308 case IPFLOOKUPITER_LIST :
1309 err = COPYOUT(nextiph, ilp->ili_data, sizeof(*nextiph));
1315 WRITE_ENTER(&softc->ipf_poolrw);
1316 ipf_htable_deref(softc, softh, iph);
1317 RWLOCK_EXIT(&softc->ipf_poolrw);
1321 case IPFLOOKUPITER_NODE :
1322 err = COPYOUT(nextnode, ilp->ili_data, sizeof(*nextnode));
1328 WRITE_ENTER(&softc->ipf_poolrw);
1329 ipf_htent_deref(softc, node);
1330 RWLOCK_EXIT(&softc->ipf_poolrw);
1336 ipf_token_mark_complete(token);
1342 /* ------------------------------------------------------------------------ */
1343 /* Function: ipf_htable_iter_deref */
1344 /* Returns: int - 0 = success, else error */
1345 /* Parameters: softc(I) - pointer to soft context main structure */
1346 /* arg(I) - pointer to local context to use */
1347 /* otype(I) - which data structure type is being walked */
1348 /* unit(I) - ipfilter device to which we are working on */
1349 /* data(I) - pointer to old data structure */
1351 /* ------------------------------------------------------------------------ */
1353 ipf_htable_iter_deref(softc, arg, otype, unit, data)
1354 ipf_main_softc_t *softc;
1364 if (unit < -1 || unit > IPL_LOGMAX)
1369 case IPFLOOKUPITER_LIST :
1370 ipf_htable_deref(softc, arg, (iphtable_t *)data);
1373 case IPFLOOKUPITER_NODE :
1374 ipf_htent_deref(arg, (iphtent_t *)data);
1385 /* ------------------------------------------------------------------------ */
1386 /* Function: ipf_iphmfind6 */
1387 /* Parameters: iph(I) - pointer to hash table */
1388 /* addr(I) - pointer to IPv6 address */
1389 /* Locks: ipf_poolrw */
1391 /* ------------------------------------------------------------------------ */
1393 ipf_iphmfind6(iph, addr)
1404 msk = iph->iph_v6_masks.imt6_active + i;
1405 ips.i6[0] = addr->i6[0] & msk->i6[0];
1406 ips.i6[1] = addr->i6[1] & msk->i6[1];
1407 ips.i6[2] = addr->i6[2] & msk->i6[2];
1408 ips.i6[3] = addr->i6[3] & msk->i6[3];
1409 hv = IPE_V6_HASH_FN(ips.i6, msk->i6, iph->iph_size);
1410 for (ipe = iph->iph_table[hv]; (ipe != NULL); ipe = ipe->ipe_next) {
1411 if ((ipe->ipe_family != AF_INET6) ||
1412 IP6_NEQ(&ipe->ipe_mask, msk) ||
1413 IP6_NEQ(&ipe->ipe_addr, &ips)) {
1421 if (i < iph->iph_v6_masks.imt6_max)
1430 ipf_htable_expire(softc, arg)
1431 ipf_main_softc_t *softc;
1434 ipf_htable_softc_t *softh = arg;
1437 while ((n = softh->ipf_node_explist) != NULL) {
1438 if (n->ipe_die > softc->ipf_ticks)
1441 ipf_htent_remove(softc, softh, n->ipe_owner, n);
1448 /* ------------------------------------------------------------------------ */
1450 /* ------------------------------------------------------------------------ */
1452 ipf_htable_dump(softc, arg)
1453 ipf_main_softc_t *softc;
1456 ipf_htable_softc_t *softh = arg;
1460 printf("List of configured hash tables\n");
1461 for (i = 0; i < IPL_LOGSIZE; i++)
1462 for (iph = softh->ipf_htables[i]; iph != NULL;
1463 iph = iph->iph_next)
1464 printhash(iph, bcopywrap, NULL, opts, NULL);