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>
26 #include <sys/socket.h>
27 #if defined(__FreeBSD_version)
28 # include <sys/malloc.h>
30 #if defined(__FreeBSD__)
31 # include <sys/cdefs.h>
32 # include <sys/proc.h>
35 # include <sys/mbuf.h>
38 # include <sys/systm.h>
42 #include <netinet/in.h>
45 #include "netinet/ip_compat.h"
46 #include "netinet/ip_fil.h"
47 #include "netinet/ip_lookup.h"
48 #include "netinet/ip_htable.h"
52 static const char rcsid[] = "@(#)$Id$";
56 static iphtent_t *ipf_iphmfind6 __P((iphtable_t *, i6addr_t *));
58 static iphtent_t *ipf_iphmfind __P((iphtable_t *, struct in_addr *));
59 static int ipf_iphmfindip __P((ipf_main_softc_t *, void *, int, void *, u_int));
60 static int ipf_htable_clear __P((ipf_main_softc_t *, void *, iphtable_t *));
61 static int ipf_htable_create __P((ipf_main_softc_t *, void *, iplookupop_t *));
62 static int ipf_htable_deref __P((ipf_main_softc_t *, void *, void *));
63 static int ipf_htable_destroy __P((ipf_main_softc_t *, void *, int, char *));
64 static void *ipf_htable_exists __P((void *, int, char *));
65 static size_t ipf_htable_flush __P((ipf_main_softc_t *, void *,
67 static void ipf_htable_free __P((void *, iphtable_t *));
68 static int ipf_htable_iter_deref __P((ipf_main_softc_t *, void *, int,
70 static int ipf_htable_iter_next __P((ipf_main_softc_t *, void *, ipftoken_t *,
72 static int ipf_htable_node_add __P((ipf_main_softc_t *, void *,
73 iplookupop_t *, int));
74 static int ipf_htable_node_del __P((ipf_main_softc_t *, void *,
75 iplookupop_t *, int));
76 static int ipf_htable_remove __P((ipf_main_softc_t *, void *, iphtable_t *));
77 static void *ipf_htable_soft_create __P((ipf_main_softc_t *));
78 static void ipf_htable_soft_destroy __P((ipf_main_softc_t *, void *));
79 static int ipf_htable_soft_init __P((ipf_main_softc_t *, void *));
80 static void ipf_htable_soft_fini __P((ipf_main_softc_t *, void *));
81 static int ipf_htable_stats_get __P((ipf_main_softc_t *, void *,
83 static int ipf_htable_table_add __P((ipf_main_softc_t *, void *,
85 static int ipf_htable_table_del __P((ipf_main_softc_t *, void *,
87 static int ipf_htent_deref __P((void *, iphtent_t *));
88 static iphtent_t *ipf_htent_find __P((iphtable_t *, iphtent_t *));
89 static int ipf_htent_insert __P((ipf_main_softc_t *, void *, iphtable_t *,
91 static int ipf_htent_remove __P((ipf_main_softc_t *, void *, iphtable_t *,
93 static void *ipf_htable_select_add_ref __P((void *, int, char *));
94 static void ipf_htable_expire __P((ipf_main_softc_t *, void *));
97 typedef struct ipf_htable_softc_s {
98 u_long ipht_nomem[LOOKUP_POOL_SZ];
99 u_long ipf_nhtables[LOOKUP_POOL_SZ];
100 u_long ipf_nhtnodes[LOOKUP_POOL_SZ];
101 iphtable_t *ipf_htables[LOOKUP_POOL_SZ];
102 iphtent_t *ipf_node_explist;
103 } ipf_htable_softc_t;
105 ipf_lookup_t ipf_htable_backend = {
107 ipf_htable_soft_create,
108 ipf_htable_soft_destroy,
109 ipf_htable_soft_init,
110 ipf_htable_soft_fini,
113 ipf_htable_iter_deref,
114 ipf_htable_iter_next,
117 ipf_htable_stats_get,
118 ipf_htable_table_add,
119 ipf_htable_table_del,
122 ipf_htable_select_add_ref,
129 /* ------------------------------------------------------------------------ */
130 /* Function: ipf_htable_soft_create */
131 /* Returns: void * - NULL = failure, else pointer to local context */
132 /* Parameters: softc(I) - pointer to soft context main structure */
134 /* Initialise the routing table data structures where required. */
135 /* ------------------------------------------------------------------------ */
137 ipf_htable_soft_create(softc)
138 ipf_main_softc_t *softc;
140 ipf_htable_softc_t *softh;
142 KMALLOC(softh, ipf_htable_softc_t *);
148 bzero((char *)softh, sizeof(*softh));
154 /* ------------------------------------------------------------------------ */
155 /* Function: ipf_htable_soft_destroy */
157 /* Parameters: softc(I) - pointer to soft context main structure */
158 /* arg(I) - pointer to local context to use */
160 /* Clean up the pool by free'ing the radix tree associated with it and free */
161 /* up the pool context too. */
162 /* ------------------------------------------------------------------------ */
164 ipf_htable_soft_destroy(softc, arg)
165 ipf_main_softc_t *softc;
168 ipf_htable_softc_t *softh = arg;
174 /* ------------------------------------------------------------------------ */
175 /* Function: ipf_htable_soft_init */
176 /* Returns: int - 0 = success, else error */
177 /* Parameters: softc(I) - pointer to soft context main structure */
178 /* arg(I) - pointer to local context to use */
180 /* Initialise the hash table ready for use. */
181 /* ------------------------------------------------------------------------ */
183 ipf_htable_soft_init(softc, arg)
184 ipf_main_softc_t *softc;
187 ipf_htable_softc_t *softh = arg;
189 bzero((char *)softh, sizeof(*softh));
195 /* ------------------------------------------------------------------------ */
196 /* Function: ipf_htable_soft_fini */
198 /* Parameters: softc(I) - pointer to soft context main structure */
199 /* arg(I) - pointer to local context to use */
200 /* Locks: WRITE(ipf_global) */
202 /* Clean up all the pool data structures allocated and call the cleanup */
203 /* function for the radix tree that supports the pools. ipf_pool_destroy is */
204 /* used to delete the pools one by one to ensure they're properly freed up. */
205 /* ------------------------------------------------------------------------ */
207 ipf_htable_soft_fini(softc, arg)
208 ipf_main_softc_t *softc;
213 fop.iplf_type = IPLT_HASH;
214 fop.iplf_unit = IPL_LOGALL;
217 *fop.iplf_name = '\0';
218 ipf_htable_flush(softc, arg, &fop);
222 /* ------------------------------------------------------------------------ */
223 /* Function: ipf_htable_stats_get */
224 /* Returns: int - 0 = success, else error */
225 /* Parameters: softc(I) - pointer to soft context main structure */
226 /* arg(I) - pointer to local context to use */
227 /* op(I) - pointer to lookup operation data */
229 /* Copy the relevant statistics out of internal structures and into the */
230 /* structure used to export statistics. */
231 /* ------------------------------------------------------------------------ */
233 ipf_htable_stats_get(softc, arg, op)
234 ipf_main_softc_t *softc;
238 ipf_htable_softc_t *softh = arg;
242 if (op->iplo_size != sizeof(stats)) {
247 stats.iphs_tables = softh->ipf_htables[op->iplo_unit + 1];
248 stats.iphs_numtables = softh->ipf_nhtables[op->iplo_unit + 1];
249 stats.iphs_numnodes = softh->ipf_nhtnodes[op->iplo_unit + 1];
250 stats.iphs_nomem = softh->ipht_nomem[op->iplo_unit + 1];
252 err = COPYOUT(&stats, op->iplo_struct, sizeof(stats));
262 /* ------------------------------------------------------------------------ */
263 /* Function: ipf_htable_create */
264 /* Returns: int - 0 = success, else error */
265 /* Parameters: softc(I) - pointer to soft context main structure */
266 /* arg(I) - pointer to local context to use */
267 /* op(I) - pointer to lookup operation data */
269 /* Create a new hash table using the template passed. */
270 /* ------------------------------------------------------------------------ */
272 ipf_htable_create(softc, arg, op)
273 ipf_main_softc_t *softc;
277 ipf_htable_softc_t *softh = arg;
278 iphtable_t htab, *iph, *oiph;
279 char name[FR_GROUPLEN];
282 if (op->iplo_size != sizeof(htab)) {
286 err = COPYIN(op->iplo_struct, &htab, sizeof(htab));
292 unit = op->iplo_unit;
293 if (htab.iph_unit != unit) {
297 if (htab.iph_size < 1) {
303 if ((op->iplo_arg & IPHASH_ANON) == 0) {
304 iph = ipf_htable_exists(softh, unit, op->iplo_name);
306 if ((iph->iph_flags & IPHASH_DELETE) == 0) {
310 iph->iph_flags &= ~IPHASH_DELETE;
316 KMALLOC(iph, iphtable_t *);
318 softh->ipht_nomem[op->iplo_unit + 1]++;
324 if ((op->iplo_arg & IPHASH_ANON) != 0) {
328 #if defined(SNPRINTF) && defined(_KERNEL)
329 SNPRINTF(name, sizeof(name), "%u", i);
331 (void)sprintf(name, "%u", i);
333 for (oiph = softh->ipf_htables[unit + 1]; oiph != NULL;
334 oiph = oiph->iph_next)
335 if (strncmp(oiph->iph_name, name,
336 sizeof(oiph->iph_name)) == 0)
338 } while (oiph != NULL);
340 (void)strncpy(iph->iph_name, name, sizeof(iph->iph_name));
341 (void)strncpy(op->iplo_name, name, sizeof(op->iplo_name));
342 iph->iph_type |= IPHASH_ANON;
344 (void)strncpy(iph->iph_name, op->iplo_name,
345 sizeof(iph->iph_name));
346 iph->iph_name[sizeof(iph->iph_name) - 1] = '\0';
349 KMALLOCS(iph->iph_table, iphtent_t **,
350 iph->iph_size * sizeof(*iph->iph_table));
351 if (iph->iph_table == NULL) {
353 softh->ipht_nomem[unit + 1]++;
358 bzero((char *)iph->iph_table, iph->iph_size * sizeof(*iph->iph_table));
359 iph->iph_maskset[0] = 0;
360 iph->iph_maskset[1] = 0;
361 iph->iph_maskset[2] = 0;
362 iph->iph_maskset[3] = 0;
365 iph->iph_list = NULL;
366 iph->iph_tail = &iph->iph_list;
367 iph->iph_next = softh->ipf_htables[unit + 1];
368 iph->iph_pnext = &softh->ipf_htables[unit + 1];
369 if (softh->ipf_htables[unit + 1] != NULL)
370 softh->ipf_htables[unit + 1]->iph_pnext = &iph->iph_next;
371 softh->ipf_htables[unit + 1] = iph;
373 softh->ipf_nhtables[unit + 1]++;
379 /* ------------------------------------------------------------------------ */
380 /* Function: ipf_htable_table_del */
381 /* Returns: int - 0 = success, else error */
382 /* Parameters: softc(I) - pointer to soft context main structure */
383 /* arg(I) - pointer to local context to use */
384 /* op(I) - pointer to lookup operation data */
386 /* ------------------------------------------------------------------------ */
388 ipf_htable_table_del(softc, arg, op)
389 ipf_main_softc_t *softc;
393 return ipf_htable_destroy(softc, arg, op->iplo_unit, op->iplo_name);
397 /* ------------------------------------------------------------------------ */
398 /* Function: ipf_htable_destroy */
399 /* Returns: int - 0 = success, else error */
400 /* Parameters: softc(I) - pointer to soft context main structure */
401 /* arg(I) - pointer to local context to use */
402 /* op(I) - pointer to lookup operation data */
404 /* Find the hash table that belongs to the relevant part of ipfilter with a */
405 /* matching name and attempt to destroy it. If it is in use, empty it out */
406 /* and mark it for deletion so that when all the references disappear, it */
407 /* can be removed. */
408 /* ------------------------------------------------------------------------ */
410 ipf_htable_destroy(softc, arg, unit, name)
411 ipf_main_softc_t *softc;
418 iph = ipf_htable_find(arg, unit, name);
424 if (iph->iph_unit != unit) {
429 if (iph->iph_ref != 0) {
430 ipf_htable_clear(softc, arg, iph);
431 iph->iph_flags |= IPHASH_DELETE;
435 ipf_htable_remove(softc, arg, iph);
441 /* ------------------------------------------------------------------------ */
442 /* Function: ipf_htable_clear */
443 /* Returns: int - 0 = success, else error */
444 /* Parameters: softc(I) - pointer to soft context main structure */
445 /* arg(I) - pointer to local context to use */
446 /* iph(I) - pointer to hash table to destroy */
448 /* Clean out the hash table by walking the list of entries and removing */
449 /* each one, one by one. */
450 /* ------------------------------------------------------------------------ */
452 ipf_htable_clear(softc, arg, iph)
453 ipf_main_softc_t *softc;
459 while ((ipe = iph->iph_list) != NULL)
460 if (ipf_htent_remove(softc, arg, iph, ipe) != 0)
466 /* ------------------------------------------------------------------------ */
467 /* Function: ipf_htable_free */
469 /* Parameters: arg(I) - pointer to local context to use */
470 /* iph(I) - pointer to hash table to destroy */
472 /* ------------------------------------------------------------------------ */
474 ipf_htable_free(arg, iph)
478 ipf_htable_softc_t *softh = arg;
480 if (iph->iph_next != NULL)
481 iph->iph_next->iph_pnext = iph->iph_pnext;
482 if (iph->iph_pnext != NULL)
483 *iph->iph_pnext = iph->iph_next;
484 iph->iph_pnext = NULL;
485 iph->iph_next = NULL;
487 softh->ipf_nhtables[iph->iph_unit + 1]--;
489 KFREES(iph->iph_table, iph->iph_size * sizeof(*iph->iph_table));
494 /* ------------------------------------------------------------------------ */
495 /* Function: ipf_htable_remove */
496 /* Returns: int - 0 = success, else error */
497 /* Parameters: softc(I) - pointer to soft context main structure */
498 /* arg(I) - pointer to local context to use */
499 /* iph(I) - pointer to hash table to destroy */
501 /* It is necessary to unlink here as well as free (called by deref) so that */
502 /* the while loop in ipf_htable_flush() functions properly. */
503 /* ------------------------------------------------------------------------ */
505 ipf_htable_remove(softc, arg, iph)
506 ipf_main_softc_t *softc;
511 if (ipf_htable_clear(softc, arg, iph) != 0)
514 if (iph->iph_pnext != NULL)
515 *iph->iph_pnext = iph->iph_next;
516 if (iph->iph_next != NULL)
517 iph->iph_next->iph_pnext = iph->iph_pnext;
518 iph->iph_pnext = NULL;
519 iph->iph_next = NULL;
521 return ipf_htable_deref(softc, arg, iph);
525 /* ------------------------------------------------------------------------ */
526 /* Function: ipf_htable_node_del */
527 /* Returns: int - 0 = success, else error */
528 /* Parameters: softc(I) - pointer to soft context main structure */
529 /* arg(I) - pointer to local context to use */
530 /* op(I) - pointer to lookup operation data */
531 /* uid(I) - real uid of process doing operation */
533 /* ------------------------------------------------------------------------ */
535 ipf_htable_node_del(softc, arg, op, uid)
536 ipf_main_softc_t *softc;
545 if (op->iplo_size != sizeof(hte)) {
550 err = COPYIN(op->iplo_struct, &hte, sizeof(hte));
556 iph = ipf_htable_find(arg, op->iplo_unit, op->iplo_name);
562 ent = ipf_htent_find(iph, &hte);
568 if ((uid != 0) && (ent->ipe_uid != uid)) {
573 err = ipf_htent_remove(softc, arg, iph, ent);
579 /* ------------------------------------------------------------------------ */
580 /* Function: ipf_htable_node_del */
581 /* Returns: int - 0 = success, else error */
582 /* Parameters: softc(I) - pointer to soft context main structure */
583 /* arg(I) - pointer to local context to use */
584 /* op(I) - pointer to lookup operation data */
586 /* ------------------------------------------------------------------------ */
588 ipf_htable_table_add(softc, arg, op)
589 ipf_main_softc_t *softc;
595 if (ipf_htable_find(arg, op->iplo_unit, op->iplo_name) != NULL) {
599 err = ipf_htable_create(softc, arg, op);
606 /* ------------------------------------------------------------------------ */
607 /* Function: ipf_htent_remove */
608 /* Returns: int - 0 = success, else error */
609 /* Parameters: softc(I) - pointer to soft context main structure */
610 /* arg(I) - pointer to local context to use */
611 /* iph(I) - pointer to hash table */
612 /* ipe(I) - pointer to hash table entry to remove */
614 /* Delete an entry from a hash table. */
615 /* ------------------------------------------------------------------------ */
617 ipf_htent_remove(softc, arg, iph, ipe)
618 ipf_main_softc_t *softc;
624 if (iph->iph_tail == &ipe->ipe_next)
625 iph->iph_tail = ipe->ipe_pnext;
627 if (ipe->ipe_hnext != NULL)
628 ipe->ipe_hnext->ipe_phnext = ipe->ipe_phnext;
629 if (ipe->ipe_phnext != NULL)
630 *ipe->ipe_phnext = ipe->ipe_hnext;
631 ipe->ipe_phnext = NULL;
632 ipe->ipe_hnext = NULL;
634 if (ipe->ipe_dnext != NULL)
635 ipe->ipe_dnext->ipe_pdnext = ipe->ipe_pdnext;
636 if (ipe->ipe_pdnext != NULL)
637 *ipe->ipe_pdnext = ipe->ipe_dnext;
638 ipe->ipe_pdnext = NULL;
639 ipe->ipe_dnext = NULL;
641 if (ipe->ipe_next != NULL)
642 ipe->ipe_next->ipe_pnext = ipe->ipe_pnext;
643 if (ipe->ipe_pnext != NULL)
644 *ipe->ipe_pnext = ipe->ipe_next;
645 ipe->ipe_pnext = NULL;
646 ipe->ipe_next = NULL;
648 switch (iph->iph_type & ~IPHASH_ANON)
650 case IPHASH_GROUPMAP :
651 if (ipe->ipe_group != NULL)
652 ipf_group_del(softc, ipe->ipe_ptr, NULL);
661 return ipf_htent_deref(arg, ipe);
665 /* ------------------------------------------------------------------------ */
666 /* Function: ipf_htable_deref */
667 /* Returns: int - 0 = success, else error */
668 /* Parameters: softc(I) - pointer to soft context main structure */
669 /* arg(I) - pointer to local context to use */
670 /* object(I) - pointer to hash table */
672 /* ------------------------------------------------------------------------ */
674 ipf_htable_deref(softc, arg, object)
675 ipf_main_softc_t *softc;
678 ipf_htable_softc_t *softh = arg;
679 iphtable_t *iph = object;
685 if (iph->iph_ref == 0) {
686 ipf_htable_free(softh, iph);
693 /* ------------------------------------------------------------------------ */
694 /* Function: ipf_htent_deref */
695 /* Parameters: arg(I) - pointer to local context to use */
698 /* ------------------------------------------------------------------------ */
700 ipf_htent_deref(arg, ipe)
704 ipf_htable_softc_t *softh = arg;
707 if (ipe->ipe_ref == 0) {
708 softh->ipf_nhtnodes[ipe->ipe_unit + 1]--;
718 /* ------------------------------------------------------------------------ */
719 /* Function: ipf_htable_exists */
720 /* Parameters: arg(I) - pointer to local context to use */
722 /* ------------------------------------------------------------------------ */
724 ipf_htable_exists(arg, unit, name)
729 ipf_htable_softc_t *softh = arg;
732 if (unit == IPL_LOGALL) {
735 for (i = 0; i <= LOOKUP_POOL_MAX; i++) {
736 for (iph = softh->ipf_htables[i]; iph != NULL;
737 iph = iph->iph_next) {
738 if (strncmp(iph->iph_name, name,
739 sizeof(iph->iph_name)) == 0)
746 for (iph = softh->ipf_htables[unit + 1]; iph != NULL;
747 iph = iph->iph_next) {
748 if (strncmp(iph->iph_name, name,
749 sizeof(iph->iph_name)) == 0)
757 /* ------------------------------------------------------------------------ */
758 /* Function: ipf_htable_select_add_ref */
759 /* Returns: void * - NULL = failure, else pointer to the hash table */
760 /* Parameters: arg(I) - pointer to local context to use */
761 /* unit(I) - ipfilter device to which we are working on */
762 /* name(I) - name of the hash table */
764 /* ------------------------------------------------------------------------ */
766 ipf_htable_select_add_ref(arg, unit, name)
773 iph = ipf_htable_exists(arg, unit, name);
775 ATOMIC_INC32(iph->iph_ref);
781 /* ------------------------------------------------------------------------ */
782 /* Function: ipf_htable_find */
783 /* Returns: void * - NULL = failure, else pointer to the hash table */
784 /* Parameters: arg(I) - pointer to local context to use */
785 /* unit(I) - ipfilter device to which we are working on */
786 /* name(I) - name of the hash table */
788 /* This function is exposed becaues it is used in the group-map feature. */
789 /* ------------------------------------------------------------------------ */
791 ipf_htable_find(arg, unit, name)
798 iph = ipf_htable_exists(arg, unit, name);
799 if ((iph != NULL) && (iph->iph_flags & IPHASH_DELETE) == 0)
806 /* ------------------------------------------------------------------------ */
807 /* Function: ipf_htable_flush */
808 /* Returns: size_t - number of entries flushed */
809 /* Parameters: softc(I) - pointer to soft context main structure */
810 /* arg(I) - pointer to local context to use */
811 /* op(I) - pointer to lookup operation data */
813 /* ------------------------------------------------------------------------ */
815 ipf_htable_flush(softc, arg, op)
816 ipf_main_softc_t *softc;
820 ipf_htable_softc_t *softh = arg;
827 for (i = -1; i <= IPL_LOGMAX; i++) {
828 if (op->iplf_unit == i || op->iplf_unit == IPL_LOGALL) {
829 while ((iph = softh->ipf_htables[i + 1]) != NULL) {
830 if (ipf_htable_remove(softc, arg, iph) == 0) {
833 iph->iph_flags |= IPHASH_DELETE;
843 /* ------------------------------------------------------------------------ */
844 /* Function: ipf_htable_node_add */
845 /* Returns: int - 0 = success, else error */
846 /* Parameters: softc(I) - pointer to soft context main structure */
847 /* arg(I) - pointer to local context to use */
848 /* op(I) - pointer to lookup operation data */
849 /* uid(I) - real uid of process doing operation */
851 /* ------------------------------------------------------------------------ */
853 ipf_htable_node_add(softc, arg, op, uid)
854 ipf_main_softc_t *softc;
863 if (op->iplo_size != sizeof(hte)) {
868 err = COPYIN(op->iplo_struct, &hte, sizeof(hte));
875 iph = ipf_htable_find(arg, op->iplo_unit, op->iplo_name);
881 if (ipf_htent_find(iph, &hte) != NULL) {
886 err = ipf_htent_insert(softc, arg, iph, &hte);
892 /* ------------------------------------------------------------------------ */
893 /* Function: ipf_htent_insert */
894 /* Returns: int - 0 = success, -1 = error */
895 /* Parameters: softc(I) - pointer to soft context main structure */
896 /* arg(I) - pointer to local context to use */
897 /* op(I) - pointer to lookup operation data */
900 /* Add an entry to a hash table. */
901 /* ------------------------------------------------------------------------ */
903 ipf_htent_insert(softc, arg, iph, ipeo)
904 ipf_main_softc_t *softc;
909 ipf_htable_softc_t *softh = arg;
914 KMALLOC(ipe, iphtent_t *);
918 bcopy((char *)ipeo, (char *)ipe, sizeof(*ipe));
919 ipe->ipe_addr.i6[0] &= ipe->ipe_mask.i6[0];
920 if (ipe->ipe_family == AF_INET) {
921 bits = count4bits(ipe->ipe_mask.in4_addr);
922 ipe->ipe_addr.i6[1] = 0;
923 ipe->ipe_addr.i6[2] = 0;
924 ipe->ipe_addr.i6[3] = 0;
925 ipe->ipe_mask.i6[1] = 0;
926 ipe->ipe_mask.i6[2] = 0;
927 ipe->ipe_mask.i6[3] = 0;
928 hv = IPE_V4_HASH_FN(ipe->ipe_addr.in4_addr,
929 ipe->ipe_mask.in4_addr, iph->iph_size);
932 if (ipe->ipe_family == AF_INET6) {
933 ipe->ipe_addr.i6[1] &= ipe->ipe_mask.i6[1];
934 ipe->ipe_addr.i6[2] &= ipe->ipe_mask.i6[2];
935 ipe->ipe_addr.i6[3] &= ipe->ipe_mask.i6[3];
937 bits = count6bits(ipe->ipe_mask.i6);
938 hv = IPE_V6_HASH_FN(ipe->ipe_addr.i6,
939 ipe->ipe_mask.i6, iph->iph_size);
947 ipe->ipe_owner = iph;
949 ipe->ipe_hnext = iph->iph_table[hv];
950 ipe->ipe_phnext = iph->iph_table + hv;
952 if (iph->iph_table[hv] != NULL)
953 iph->iph_table[hv]->ipe_phnext = &ipe->ipe_hnext;
954 iph->iph_table[hv] = ipe;
956 ipe->ipe_pnext = iph->iph_tail;
957 *iph->iph_tail = ipe;
958 iph->iph_tail = &ipe->ipe_next;
959 ipe->ipe_next = NULL;
961 if (ipe->ipe_die != 0) {
963 * If the new node has a given expiration time, insert it
964 * into the list of expiring nodes with the ones to be
965 * removed first added to the front of the list. The
966 * insertion is O(n) but it is kept sorted for quick scans
967 * at expiration interval checks.
971 ipe->ipe_die = softc->ipf_ticks + IPF_TTLVAL(ipe->ipe_die);
972 for (n = softh->ipf_node_explist; n != NULL; n = n->ipe_dnext) {
973 if (ipe->ipe_die < n->ipe_die)
975 if (n->ipe_dnext == NULL) {
977 * We've got to the last node and everything
978 * wanted to be expired before this new node,
979 * so we have to tack it on the end...
982 ipe->ipe_pdnext = &n->ipe_dnext;
988 if (softh->ipf_node_explist == NULL) {
989 softh->ipf_node_explist = ipe;
990 ipe->ipe_pdnext = &softh->ipf_node_explist;
991 } else if (n != NULL) {
993 ipe->ipe_pdnext = n->ipe_pdnext;
994 n->ipe_pdnext = &ipe->ipe_dnext;
998 if (ipe->ipe_family == AF_INET) {
999 ipf_inet_mask_add(bits, &iph->iph_v4_masks);
1002 else if (ipe->ipe_family == AF_INET6) {
1003 ipf_inet6_mask_add(bits, &ipe->ipe_mask, &iph->iph_v6_masks);
1007 switch (iph->iph_type & ~IPHASH_ANON)
1009 case IPHASH_GROUPMAP :
1010 ipe->ipe_ptr = ipf_group_add(softc, ipe->ipe_group, NULL,
1011 iph->iph_flags, IPL_LOGIPF,
1016 ipe->ipe_ptr = NULL;
1021 ipe->ipe_unit = iph->iph_unit;
1022 softh->ipf_nhtnodes[ipe->ipe_unit + 1]++;
1028 /* ------------------------------------------------------------------------ */
1029 /* Function: ipf_htent_find */
1030 /* Returns: int - 0 = success, else error */
1031 /* Parameters: iph(I) - pointer to table to search */
1032 /* ipeo(I) - pointer to entry to find */
1034 /* While it isn't absolutely necessary to for the address and mask to be */
1035 /* passed in through an iphtent_t structure, one is always present when it */
1036 /* is time to call this function, so it is just more convenient. */
1037 /* ------------------------------------------------------------------------ */
1039 ipf_htent_find(iph, ipeo)
1043 iphtent_t ipe, *ent;
1047 bcopy((char *)ipeo, (char *)&ipe, sizeof(ipe));
1048 ipe.ipe_addr.i6[0] &= ipe.ipe_mask.i6[0];
1049 ipe.ipe_addr.i6[1] &= ipe.ipe_mask.i6[1];
1050 ipe.ipe_addr.i6[2] &= ipe.ipe_mask.i6[2];
1051 ipe.ipe_addr.i6[3] &= ipe.ipe_mask.i6[3];
1052 if (ipe.ipe_family == AF_INET) {
1053 bits = count4bits(ipe.ipe_mask.in4_addr);
1054 ipe.ipe_addr.i6[1] = 0;
1055 ipe.ipe_addr.i6[2] = 0;
1056 ipe.ipe_addr.i6[3] = 0;
1057 ipe.ipe_mask.i6[1] = 0;
1058 ipe.ipe_mask.i6[2] = 0;
1059 ipe.ipe_mask.i6[3] = 0;
1060 hv = IPE_V4_HASH_FN(ipe.ipe_addr.in4_addr,
1061 ipe.ipe_mask.in4_addr, iph->iph_size);
1064 if (ipe.ipe_family == AF_INET6) {
1065 bits = count6bits(ipe.ipe_mask.i6);
1066 hv = IPE_V6_HASH_FN(ipe.ipe_addr.i6,
1067 ipe.ipe_mask.i6, iph->iph_size);
1072 for (ent = iph->iph_table[hv]; ent != NULL; ent = ent->ipe_hnext) {
1073 if (ent->ipe_family != ipe.ipe_family)
1075 if (IP6_NEQ(&ipe.ipe_addr, &ent->ipe_addr))
1077 if (IP6_NEQ(&ipe.ipe_mask, &ent->ipe_mask))
1086 /* ------------------------------------------------------------------------ */
1087 /* Function: ipf_iphmfindgroup */
1088 /* Returns: int - 0 = success, else error */
1089 /* Parameters: softc(I) - pointer to soft context main structure */
1093 /* Search a hash table for a matching entry and return the pointer stored */
1094 /* in it for use as the next group of rules to search. */
1096 /* This function is exposed becaues it is used in the group-map feature. */
1097 /* ------------------------------------------------------------------------ */
1099 ipf_iphmfindgroup(softc, tptr, aptr)
1100 ipf_main_softc_t *softc;
1103 struct in_addr *addr;
1108 READ_ENTER(&softc->ipf_poolrw);
1112 ipe = ipf_iphmfind(iph, addr);
1114 rval = ipe->ipe_ptr;
1117 RWLOCK_EXIT(&softc->ipf_poolrw);
1122 /* ------------------------------------------------------------------------ */
1123 /* Function: ipf_iphmfindip */
1124 /* Returns: int - 0 == +ve match, -1 == error, 1 == -ve/no match */
1125 /* Parameters: softc(I) - pointer to soft context main structure */
1126 /* tptr(I) - pointer to the pool to search */
1127 /* ipversion(I) - IP protocol version (4 or 6) */
1128 /* aptr(I) - pointer to address information */
1129 /* bytes(I) - packet length */
1131 /* Search the hash table for a given address and return a search result. */
1132 /* ------------------------------------------------------------------------ */
1134 ipf_iphmfindip(softc, tptr, ipversion, aptr, bytes)
1135 ipf_main_softc_t *softc;
1140 struct in_addr *addr;
1145 if (tptr == NULL || aptr == NULL)
1151 READ_ENTER(&softc->ipf_poolrw);
1152 if (ipversion == 4) {
1153 ipe = ipf_iphmfind(iph, addr);
1155 } else if (ipversion == 6) {
1156 ipe = ipf_iphmfind6(iph, (i6addr_t *)addr);
1165 ipe->ipe_bytes += bytes;
1169 RWLOCK_EXIT(&softc->ipf_poolrw);
1174 /* ------------------------------------------------------------------------ */
1175 /* Function: ipf_iphmfindip */
1176 /* Parameters: iph(I) - pointer to hash table */
1177 /* addr(I) - pointer to IPv4 address */
1178 /* Locks: ipf_poolrw */
1180 /* ------------------------------------------------------------------------ */
1182 ipf_iphmfind(iph, addr)
1184 struct in_addr *addr;
1193 msk = iph->iph_v4_masks.imt4_active[i];
1194 ips = addr->s_addr & msk;
1195 hv = IPE_V4_HASH_FN(ips, msk, iph->iph_size);
1196 for (ipe = iph->iph_table[hv]; (ipe != NULL); ipe = ipe->ipe_hnext) {
1197 if ((ipe->ipe_family != AF_INET) ||
1198 (ipe->ipe_mask.in4_addr != msk) ||
1199 (ipe->ipe_addr.in4_addr != ips)) {
1207 if (i < iph->iph_v4_masks.imt4_max)
1214 /* ------------------------------------------------------------------------ */
1215 /* Function: ipf_htable_iter_next */
1216 /* Returns: int - 0 = success, else error */
1217 /* Parameters: softc(I) - pointer to soft context main structure */
1218 /* arg(I) - pointer to local context to use */
1222 /* ------------------------------------------------------------------------ */
1224 ipf_htable_iter_next(softc, arg, token, ilp)
1225 ipf_main_softc_t *softc;
1228 ipflookupiter_t *ilp;
1230 ipf_htable_softc_t *softh = arg;
1231 iphtent_t *node, zn, *nextnode;
1232 iphtable_t *iph, zp, *nextiph;
1242 READ_ENTER(&softc->ipf_poolrw);
1244 switch (ilp->ili_otype)
1246 case IPFLOOKUPITER_LIST :
1247 iph = token->ipt_data;
1249 nextiph = softh->ipf_htables[(int)ilp->ili_unit + 1];
1251 nextiph = iph->iph_next;
1254 if (nextiph != NULL) {
1255 ATOMIC_INC(nextiph->iph_ref);
1256 token->ipt_data = nextiph;
1258 bzero((char *)&zp, sizeof(zp));
1260 token->ipt_data = NULL;
1262 hnext = nextiph->iph_next;
1265 case IPFLOOKUPITER_NODE :
1266 node = token->ipt_data;
1268 iph = ipf_htable_find(arg, ilp->ili_unit,
1274 nextnode = iph->iph_list;
1277 nextnode = node->ipe_next;
1280 if (nextnode != NULL) {
1281 ATOMIC_INC(nextnode->ipe_ref);
1282 token->ipt_data = nextnode;
1284 bzero((char *)&zn, sizeof(zn));
1286 token->ipt_data = NULL;
1288 hnext = nextnode->ipe_next;
1298 RWLOCK_EXIT(&softc->ipf_poolrw);
1302 switch (ilp->ili_otype)
1304 case IPFLOOKUPITER_LIST :
1305 err = COPYOUT(nextiph, ilp->ili_data, sizeof(*nextiph));
1311 WRITE_ENTER(&softc->ipf_poolrw);
1312 ipf_htable_deref(softc, softh, iph);
1313 RWLOCK_EXIT(&softc->ipf_poolrw);
1317 case IPFLOOKUPITER_NODE :
1318 err = COPYOUT(nextnode, ilp->ili_data, sizeof(*nextnode));
1324 WRITE_ENTER(&softc->ipf_poolrw);
1325 ipf_htent_deref(softc, node);
1326 RWLOCK_EXIT(&softc->ipf_poolrw);
1332 ipf_token_mark_complete(token);
1338 /* ------------------------------------------------------------------------ */
1339 /* Function: ipf_htable_iter_deref */
1340 /* Returns: int - 0 = success, else error */
1341 /* Parameters: softc(I) - pointer to soft context main structure */
1342 /* arg(I) - pointer to local context to use */
1343 /* otype(I) - which data structure type is being walked */
1344 /* unit(I) - ipfilter device to which we are working on */
1345 /* data(I) - pointer to old data structure */
1347 /* ------------------------------------------------------------------------ */
1349 ipf_htable_iter_deref(softc, arg, otype, unit, data)
1350 ipf_main_softc_t *softc;
1360 if (unit < -1 || unit > IPL_LOGMAX)
1365 case IPFLOOKUPITER_LIST :
1366 ipf_htable_deref(softc, arg, (iphtable_t *)data);
1369 case IPFLOOKUPITER_NODE :
1370 ipf_htent_deref(arg, (iphtent_t *)data);
1381 /* ------------------------------------------------------------------------ */
1382 /* Function: ipf_iphmfind6 */
1383 /* Parameters: iph(I) - pointer to hash table */
1384 /* addr(I) - pointer to IPv6 address */
1385 /* Locks: ipf_poolrw */
1387 /* ------------------------------------------------------------------------ */
1389 ipf_iphmfind6(iph, addr)
1400 msk = iph->iph_v6_masks.imt6_active + i;
1401 ips.i6[0] = addr->i6[0] & msk->i6[0];
1402 ips.i6[1] = addr->i6[1] & msk->i6[1];
1403 ips.i6[2] = addr->i6[2] & msk->i6[2];
1404 ips.i6[3] = addr->i6[3] & msk->i6[3];
1405 hv = IPE_V6_HASH_FN(ips.i6, msk->i6, iph->iph_size);
1406 for (ipe = iph->iph_table[hv]; (ipe != NULL); ipe = ipe->ipe_next) {
1407 if ((ipe->ipe_family != AF_INET6) ||
1408 IP6_NEQ(&ipe->ipe_mask, msk) ||
1409 IP6_NEQ(&ipe->ipe_addr, &ips)) {
1417 if (i < iph->iph_v6_masks.imt6_max)
1426 ipf_htable_expire(softc, arg)
1427 ipf_main_softc_t *softc;
1430 ipf_htable_softc_t *softh = arg;
1433 while ((n = softh->ipf_node_explist) != NULL) {
1434 if (n->ipe_die > softc->ipf_ticks)
1437 ipf_htent_remove(softc, softh, n->ipe_owner, n);
1444 /* ------------------------------------------------------------------------ */
1446 /* ------------------------------------------------------------------------ */
1448 ipf_htable_dump(softc, arg)
1449 ipf_main_softc_t *softc;
1452 ipf_htable_softc_t *softh = arg;
1456 printf("List of configured hash tables\n");
1457 for (i = 0; i < IPL_LOGSIZE; i++)
1458 for (iph = softh->ipf_htables[i]; iph != NULL;
1459 iph = iph->iph_next)
1460 printhash(iph, bcopywrap, NULL, opts, NULL);