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__)
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(iphtable_t *, i6addr_t *);
58 static iphtent_t *ipf_iphmfind(iphtable_t *, struct in_addr *);
59 static int ipf_iphmfindip(ipf_main_softc_t *, void *, int, void *, u_int);
60 static int ipf_htable_clear(ipf_main_softc_t *, void *, iphtable_t *);
61 static int ipf_htable_create(ipf_main_softc_t *, void *, iplookupop_t *);
62 static int ipf_htable_deref(ipf_main_softc_t *, void *, void *);
63 static int ipf_htable_destroy(ipf_main_softc_t *, void *, int, char *);
64 static void *ipf_htable_exists(void *, int, char *);
65 static size_t ipf_htable_flush(ipf_main_softc_t *, void *,
67 static void ipf_htable_free(void *, iphtable_t *);
68 static int ipf_htable_iter_deref(ipf_main_softc_t *, void *, int,
70 static int ipf_htable_iter_next(ipf_main_softc_t *, void *, ipftoken_t *,
72 static int ipf_htable_node_add(ipf_main_softc_t *, void *,
74 static int ipf_htable_node_del(ipf_main_softc_t *, void *,
76 static int ipf_htable_remove(ipf_main_softc_t *, void *, iphtable_t *);
77 static void *ipf_htable_soft_create(ipf_main_softc_t *);
78 static void ipf_htable_soft_destroy(ipf_main_softc_t *, void *);
79 static int ipf_htable_soft_init(ipf_main_softc_t *, void *);
80 static void ipf_htable_soft_fini(ipf_main_softc_t *, void *);
81 static int ipf_htable_stats_get(ipf_main_softc_t *, void *,
83 static int ipf_htable_table_add(ipf_main_softc_t *, void *,
85 static int ipf_htable_table_del(ipf_main_softc_t *, void *,
87 static int ipf_htent_deref(void *, iphtent_t *);
88 static iphtent_t *ipf_htent_find(iphtable_t *, iphtent_t *);
89 static int ipf_htent_insert(ipf_main_softc_t *, void *, iphtable_t *,
91 static int ipf_htent_remove(ipf_main_softc_t *, void *, iphtable_t *,
93 static void *ipf_htable_select_add_ref(void *, int, char *);
94 static void ipf_htable_expire(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(ipf_main_softc_t *softc)
139 ipf_htable_softc_t *softh;
141 KMALLOC(softh, ipf_htable_softc_t *);
147 bzero((char *)softh, sizeof(*softh));
153 /* ------------------------------------------------------------------------ */
154 /* Function: ipf_htable_soft_destroy */
156 /* Parameters: softc(I) - pointer to soft context main structure */
157 /* arg(I) - pointer to local context to use */
159 /* Clean up the pool by free'ing the radix tree associated with it and free */
160 /* up the pool context too. */
161 /* ------------------------------------------------------------------------ */
163 ipf_htable_soft_destroy(ipf_main_softc_t *softc, void *arg)
165 ipf_htable_softc_t *softh = arg;
171 /* ------------------------------------------------------------------------ */
172 /* Function: ipf_htable_soft_init */
173 /* Returns: int - 0 = success, else error */
174 /* Parameters: softc(I) - pointer to soft context main structure */
175 /* arg(I) - pointer to local context to use */
177 /* Initialise the hash table ready for use. */
178 /* ------------------------------------------------------------------------ */
180 ipf_htable_soft_init(softc, arg)
181 ipf_main_softc_t *softc;
184 ipf_htable_softc_t *softh = arg;
186 bzero((char *)softh, sizeof(*softh));
192 /* ------------------------------------------------------------------------ */
193 /* Function: ipf_htable_soft_fini */
195 /* Parameters: softc(I) - pointer to soft context main structure */
196 /* arg(I) - pointer to local context to use */
197 /* Locks: WRITE(ipf_global) */
199 /* Clean up all the pool data structures allocated and call the cleanup */
200 /* function for the radix tree that supports the pools. ipf_pool_destroy is */
201 /* used to delete the pools one by one to ensure they're properly freed up. */
202 /* ------------------------------------------------------------------------ */
204 ipf_htable_soft_fini(ipf_main_softc_t *softc, void *arg)
208 fop.iplf_type = IPLT_HASH;
209 fop.iplf_unit = IPL_LOGALL;
212 *fop.iplf_name = '\0';
213 ipf_htable_flush(softc, arg, &fop);
217 /* ------------------------------------------------------------------------ */
218 /* Function: ipf_htable_stats_get */
219 /* Returns: int - 0 = success, else error */
220 /* Parameters: softc(I) - pointer to soft context main structure */
221 /* arg(I) - pointer to local context to use */
222 /* op(I) - pointer to lookup operation data */
224 /* Copy the relevant statistics out of internal structures and into the */
225 /* structure used to export statistics. */
226 /* ------------------------------------------------------------------------ */
228 ipf_htable_stats_get(ipf_main_softc_t *softc, void *arg, iplookupop_t *op)
230 ipf_htable_softc_t *softh = arg;
234 if (op->iplo_size != sizeof(stats)) {
239 stats.iphs_tables = softh->ipf_htables[op->iplo_unit + 1];
240 stats.iphs_numtables = softh->ipf_nhtables[op->iplo_unit + 1];
241 stats.iphs_numnodes = softh->ipf_nhtnodes[op->iplo_unit + 1];
242 stats.iphs_nomem = softh->ipht_nomem[op->iplo_unit + 1];
244 err = COPYOUT(&stats, op->iplo_struct, sizeof(stats));
254 /* ------------------------------------------------------------------------ */
255 /* Function: ipf_htable_create */
256 /* Returns: int - 0 = success, else error */
257 /* Parameters: softc(I) - pointer to soft context main structure */
258 /* arg(I) - pointer to local context to use */
259 /* op(I) - pointer to lookup operation data */
261 /* Create a new hash table using the template passed. */
262 /* ------------------------------------------------------------------------ */
264 ipf_htable_create(ipf_main_softc_t *softc, void *arg, iplookupop_t *op)
266 ipf_htable_softc_t *softh = arg;
267 iphtable_t htab, *iph, *oiph;
268 char name[FR_GROUPLEN];
271 if (op->iplo_size != sizeof(htab)) {
275 err = COPYIN(op->iplo_struct, &htab, sizeof(htab));
281 unit = op->iplo_unit;
282 if (htab.iph_unit != unit) {
286 if (htab.iph_size < 1) {
292 if ((op->iplo_arg & IPHASH_ANON) == 0) {
293 iph = ipf_htable_exists(softh, unit, op->iplo_name);
295 if ((iph->iph_flags & IPHASH_DELETE) == 0) {
299 iph->iph_flags &= ~IPHASH_DELETE;
305 KMALLOC(iph, iphtable_t *);
307 softh->ipht_nomem[op->iplo_unit + 1]++;
313 if ((op->iplo_arg & IPHASH_ANON) != 0) {
317 (void)snprintf(name, sizeof(name), "%u", i);
318 for (oiph = softh->ipf_htables[unit + 1]; oiph != NULL;
319 oiph = oiph->iph_next)
320 if (strncmp(oiph->iph_name, name,
321 sizeof(oiph->iph_name)) == 0)
323 } while (oiph != NULL);
325 (void)strncpy(iph->iph_name, name, sizeof(iph->iph_name));
326 (void)strncpy(op->iplo_name, name, sizeof(op->iplo_name));
327 iph->iph_type |= IPHASH_ANON;
329 (void)strncpy(iph->iph_name, op->iplo_name,
330 sizeof(iph->iph_name));
331 iph->iph_name[sizeof(iph->iph_name) - 1] = '\0';
334 KMALLOCS(iph->iph_table, iphtent_t **,
335 iph->iph_size * sizeof(*iph->iph_table));
336 if (iph->iph_table == NULL) {
338 softh->ipht_nomem[unit + 1]++;
343 bzero((char *)iph->iph_table, iph->iph_size * sizeof(*iph->iph_table));
344 iph->iph_maskset[0] = 0;
345 iph->iph_maskset[1] = 0;
346 iph->iph_maskset[2] = 0;
347 iph->iph_maskset[3] = 0;
350 iph->iph_list = NULL;
351 iph->iph_tail = &iph->iph_list;
352 iph->iph_next = softh->ipf_htables[unit + 1];
353 iph->iph_pnext = &softh->ipf_htables[unit + 1];
354 if (softh->ipf_htables[unit + 1] != NULL)
355 softh->ipf_htables[unit + 1]->iph_pnext = &iph->iph_next;
356 softh->ipf_htables[unit + 1] = iph;
358 softh->ipf_nhtables[unit + 1]++;
364 /* ------------------------------------------------------------------------ */
365 /* Function: ipf_htable_table_del */
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 operation data */
371 /* ------------------------------------------------------------------------ */
373 ipf_htable_table_del(ipf_main_softc_t *softc, void *arg, iplookupop_t *op)
375 return(ipf_htable_destroy(softc, arg, op->iplo_unit, op->iplo_name));
379 /* ------------------------------------------------------------------------ */
380 /* Function: ipf_htable_destroy */
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 /* Find the hash table that belongs to the relevant part of ipfilter with a */
387 /* matching name and attempt to destroy it. If it is in use, empty it out */
388 /* and mark it for deletion so that when all the references disappear, it */
389 /* can be removed. */
390 /* ------------------------------------------------------------------------ */
392 ipf_htable_destroy(ipf_main_softc_t *softc, void *arg, int unit, char *name)
396 iph = ipf_htable_find(arg, unit, name);
402 if (iph->iph_unit != unit) {
407 if (iph->iph_ref != 0) {
408 ipf_htable_clear(softc, arg, iph);
409 iph->iph_flags |= IPHASH_DELETE;
413 ipf_htable_remove(softc, arg, iph);
419 /* ------------------------------------------------------------------------ */
420 /* Function: ipf_htable_clear */
421 /* Returns: int - 0 = success, else error */
422 /* Parameters: softc(I) - pointer to soft context main structure */
423 /* arg(I) - pointer to local context to use */
424 /* iph(I) - pointer to hash table to destroy */
426 /* Clean out the hash table by walking the list of entries and removing */
427 /* each one, one by one. */
428 /* ------------------------------------------------------------------------ */
430 ipf_htable_clear(ipf_main_softc_t *softc, void *arg, iphtable_t *iph)
434 while ((ipe = iph->iph_list) != NULL)
435 if (ipf_htent_remove(softc, arg, iph, ipe) != 0)
441 /* ------------------------------------------------------------------------ */
442 /* Function: ipf_htable_free */
444 /* Parameters: arg(I) - pointer to local context to use */
445 /* iph(I) - pointer to hash table to destroy */
447 /* ------------------------------------------------------------------------ */
449 ipf_htable_free(void *arg, iphtable_t *iph)
451 ipf_htable_softc_t *softh = arg;
453 if (iph->iph_next != NULL)
454 iph->iph_next->iph_pnext = iph->iph_pnext;
455 if (iph->iph_pnext != NULL)
456 *iph->iph_pnext = iph->iph_next;
457 iph->iph_pnext = NULL;
458 iph->iph_next = NULL;
460 softh->ipf_nhtables[iph->iph_unit + 1]--;
462 KFREES(iph->iph_table, iph->iph_size * sizeof(*iph->iph_table));
467 /* ------------------------------------------------------------------------ */
468 /* Function: ipf_htable_remove */
469 /* Returns: int - 0 = success, else error */
470 /* Parameters: softc(I) - pointer to soft context main structure */
471 /* arg(I) - pointer to local context to use */
472 /* iph(I) - pointer to hash table to destroy */
474 /* It is necessary to unlink here as well as free (called by deref) so that */
475 /* the while loop in ipf_htable_flush() functions properly. */
476 /* ------------------------------------------------------------------------ */
478 ipf_htable_remove(ipf_main_softc_t *softc, void *arg, iphtable_t *iph)
481 if (ipf_htable_clear(softc, arg, iph) != 0)
484 if (iph->iph_pnext != NULL)
485 *iph->iph_pnext = iph->iph_next;
486 if (iph->iph_next != NULL)
487 iph->iph_next->iph_pnext = iph->iph_pnext;
488 iph->iph_pnext = NULL;
489 iph->iph_next = NULL;
491 return(ipf_htable_deref(softc, arg, iph));
495 /* ------------------------------------------------------------------------ */
496 /* Function: ipf_htable_node_del */
497 /* Returns: int - 0 = success, else error */
498 /* Parameters: softc(I) - pointer to soft context main structure */
499 /* arg(I) - pointer to local context to use */
500 /* op(I) - pointer to lookup operation data */
501 /* uid(I) - real uid of process doing operation */
503 /* ------------------------------------------------------------------------ */
505 ipf_htable_node_del(ipf_main_softc_t *softc, void *arg, iplookupop_t *op,
512 if (op->iplo_size != sizeof(hte)) {
517 err = COPYIN(op->iplo_struct, &hte, sizeof(hte));
523 iph = ipf_htable_find(arg, op->iplo_unit, op->iplo_name);
529 ent = ipf_htent_find(iph, &hte);
535 if ((uid != 0) && (ent->ipe_uid != uid)) {
540 err = ipf_htent_remove(softc, arg, iph, ent);
546 /* ------------------------------------------------------------------------ */
547 /* Function: ipf_htable_node_del */
548 /* Returns: int - 0 = success, else error */
549 /* Parameters: softc(I) - pointer to soft context main structure */
550 /* arg(I) - pointer to local context to use */
551 /* op(I) - pointer to lookup operation data */
553 /* ------------------------------------------------------------------------ */
555 ipf_htable_table_add(ipf_main_softc_t *softc, void *arg, iplookupop_t *op)
559 if (ipf_htable_find(arg, op->iplo_unit, op->iplo_name) != NULL) {
563 err = ipf_htable_create(softc, arg, op);
570 /* ------------------------------------------------------------------------ */
571 /* Function: ipf_htent_remove */
572 /* Returns: int - 0 = success, else error */
573 /* Parameters: softc(I) - pointer to soft context main structure */
574 /* arg(I) - pointer to local context to use */
575 /* iph(I) - pointer to hash table */
576 /* ipe(I) - pointer to hash table entry to remove */
578 /* Delete an entry from a hash table. */
579 /* ------------------------------------------------------------------------ */
581 ipf_htent_remove(ipf_main_softc_t *softc, void *arg, iphtable_t *iph,
585 if (iph->iph_tail == &ipe->ipe_next)
586 iph->iph_tail = ipe->ipe_pnext;
588 if (ipe->ipe_hnext != NULL)
589 ipe->ipe_hnext->ipe_phnext = ipe->ipe_phnext;
590 if (ipe->ipe_phnext != NULL)
591 *ipe->ipe_phnext = ipe->ipe_hnext;
592 ipe->ipe_phnext = NULL;
593 ipe->ipe_hnext = NULL;
595 if (ipe->ipe_dnext != NULL)
596 ipe->ipe_dnext->ipe_pdnext = ipe->ipe_pdnext;
597 if (ipe->ipe_pdnext != NULL)
598 *ipe->ipe_pdnext = ipe->ipe_dnext;
599 ipe->ipe_pdnext = NULL;
600 ipe->ipe_dnext = NULL;
602 if (ipe->ipe_next != NULL)
603 ipe->ipe_next->ipe_pnext = ipe->ipe_pnext;
604 if (ipe->ipe_pnext != NULL)
605 *ipe->ipe_pnext = ipe->ipe_next;
606 ipe->ipe_pnext = NULL;
607 ipe->ipe_next = NULL;
609 switch (iph->iph_type & ~IPHASH_ANON)
611 case IPHASH_GROUPMAP :
612 if (ipe->ipe_group != NULL)
613 ipf_group_del(softc, ipe->ipe_ptr, NULL);
622 return(ipf_htent_deref(arg, ipe));
626 /* ------------------------------------------------------------------------ */
627 /* Function: ipf_htable_deref */
628 /* Returns: int - 0 = success, else error */
629 /* Parameters: softc(I) - pointer to soft context main structure */
630 /* arg(I) - pointer to local context to use */
631 /* object(I) - pointer to hash table */
633 /* ------------------------------------------------------------------------ */
635 ipf_htable_deref(ipf_main_softc_t *softc, void *arg, void *object)
637 ipf_htable_softc_t *softh = arg;
638 iphtable_t *iph = object;
644 if (iph->iph_ref == 0) {
645 ipf_htable_free(softh, iph);
652 /* ------------------------------------------------------------------------ */
653 /* Function: ipf_htent_deref */
654 /* Parameters: arg(I) - pointer to local context to use */
657 /* ------------------------------------------------------------------------ */
659 ipf_htent_deref(void *arg, iphtent_t *ipe)
661 ipf_htable_softc_t *softh = arg;
664 if (ipe->ipe_ref == 0) {
665 softh->ipf_nhtnodes[ipe->ipe_unit + 1]--;
671 return(ipe->ipe_ref);
675 /* ------------------------------------------------------------------------ */
676 /* Function: ipf_htable_exists */
677 /* Parameters: arg(I) - pointer to local context to use */
679 /* ------------------------------------------------------------------------ */
681 ipf_htable_exists(void *arg, int unit, char *name)
683 ipf_htable_softc_t *softh = arg;
686 if (unit == IPL_LOGALL) {
689 for (i = 0; i <= LOOKUP_POOL_MAX; i++) {
690 for (iph = softh->ipf_htables[i]; iph != NULL;
691 iph = iph->iph_next) {
692 if (strncmp(iph->iph_name, name,
693 sizeof(iph->iph_name)) == 0)
700 for (iph = softh->ipf_htables[unit + 1]; iph != NULL;
701 iph = iph->iph_next) {
702 if (strncmp(iph->iph_name, name,
703 sizeof(iph->iph_name)) == 0)
711 /* ------------------------------------------------------------------------ */
712 /* Function: ipf_htable_select_add_ref */
713 /* Returns: void * - NULL = failure, else pointer to the hash table */
714 /* Parameters: arg(I) - pointer to local context to use */
715 /* unit(I) - ipfilter device to which we are working on */
716 /* name(I) - name of the hash table */
718 /* ------------------------------------------------------------------------ */
720 ipf_htable_select_add_ref(void *arg, int unit, char *name)
724 iph = ipf_htable_exists(arg, unit, name);
726 ATOMIC_INC32(iph->iph_ref);
732 /* ------------------------------------------------------------------------ */
733 /* Function: ipf_htable_find */
734 /* Returns: void * - NULL = failure, else pointer to the hash table */
735 /* Parameters: arg(I) - pointer to local context to use */
736 /* unit(I) - ipfilter device to which we are working on */
737 /* name(I) - name of the hash table */
739 /* This function is exposed becaues it is used in the group-map feature. */
740 /* ------------------------------------------------------------------------ */
742 ipf_htable_find(void *arg, int unit, char *name)
746 iph = ipf_htable_exists(arg, unit, name);
747 if ((iph != NULL) && (iph->iph_flags & IPHASH_DELETE) == 0)
754 /* ------------------------------------------------------------------------ */
755 /* Function: ipf_htable_flush */
756 /* Returns: size_t - number of entries flushed */
757 /* Parameters: softc(I) - pointer to soft context main structure */
758 /* arg(I) - pointer to local context to use */
759 /* op(I) - pointer to lookup operation data */
761 /* ------------------------------------------------------------------------ */
763 ipf_htable_flush(ipf_main_softc_t *softc, void *arg, iplookupflush_t *op)
765 ipf_htable_softc_t *softh = arg;
772 for (i = -1; i <= IPL_LOGMAX; i++) {
773 if (op->iplf_unit == i || op->iplf_unit == IPL_LOGALL) {
774 while ((iph = softh->ipf_htables[i + 1]) != NULL) {
775 if (ipf_htable_remove(softc, arg, iph) == 0) {
778 iph->iph_flags |= IPHASH_DELETE;
788 /* ------------------------------------------------------------------------ */
789 /* Function: ipf_htable_node_add */
790 /* Returns: int - 0 = success, else error */
791 /* Parameters: softc(I) - pointer to soft context main structure */
792 /* arg(I) - pointer to local context to use */
793 /* op(I) - pointer to lookup operation data */
794 /* uid(I) - real uid of process doing operation */
796 /* ------------------------------------------------------------------------ */
798 ipf_htable_node_add(ipf_main_softc_t *softc, void *arg, iplookupop_t *op,
805 if (op->iplo_size != sizeof(hte)) {
810 err = COPYIN(op->iplo_struct, &hte, sizeof(hte));
817 iph = ipf_htable_find(arg, op->iplo_unit, op->iplo_name);
823 if (ipf_htent_find(iph, &hte) != NULL) {
828 err = ipf_htent_insert(softc, arg, iph, &hte);
834 /* ------------------------------------------------------------------------ */
835 /* Function: ipf_htent_insert */
836 /* Returns: int - 0 = success, -1 = error */
837 /* Parameters: softc(I) - pointer to soft context main structure */
838 /* arg(I) - pointer to local context to use */
839 /* op(I) - pointer to lookup operation data */
842 /* Add an entry to a hash table. */
843 /* ------------------------------------------------------------------------ */
845 ipf_htent_insert(ipf_main_softc_t *softc, void *arg, iphtable_t *iph,
848 ipf_htable_softc_t *softh = arg;
853 KMALLOC(ipe, iphtent_t *);
857 bcopy((char *)ipeo, (char *)ipe, sizeof(*ipe));
858 ipe->ipe_addr.i6[0] &= ipe->ipe_mask.i6[0];
859 if (ipe->ipe_family == AF_INET) {
860 bits = count4bits(ipe->ipe_mask.in4_addr);
861 ipe->ipe_addr.i6[1] = 0;
862 ipe->ipe_addr.i6[2] = 0;
863 ipe->ipe_addr.i6[3] = 0;
864 ipe->ipe_mask.i6[1] = 0;
865 ipe->ipe_mask.i6[2] = 0;
866 ipe->ipe_mask.i6[3] = 0;
867 hv = IPE_V4_HASH_FN(ipe->ipe_addr.in4_addr,
868 ipe->ipe_mask.in4_addr, iph->iph_size);
871 if (ipe->ipe_family == AF_INET6) {
872 ipe->ipe_addr.i6[1] &= ipe->ipe_mask.i6[1];
873 ipe->ipe_addr.i6[2] &= ipe->ipe_mask.i6[2];
874 ipe->ipe_addr.i6[3] &= ipe->ipe_mask.i6[3];
876 bits = count6bits(ipe->ipe_mask.i6);
877 hv = IPE_V6_HASH_FN(ipe->ipe_addr.i6,
878 ipe->ipe_mask.i6, iph->iph_size);
886 ipe->ipe_owner = iph;
888 ipe->ipe_hnext = iph->iph_table[hv];
889 ipe->ipe_phnext = iph->iph_table + hv;
891 if (iph->iph_table[hv] != NULL)
892 iph->iph_table[hv]->ipe_phnext = &ipe->ipe_hnext;
893 iph->iph_table[hv] = ipe;
895 ipe->ipe_pnext = iph->iph_tail;
896 *iph->iph_tail = ipe;
897 iph->iph_tail = &ipe->ipe_next;
898 ipe->ipe_next = NULL;
900 if (ipe->ipe_die != 0) {
902 * If the new node has a given expiration time, insert it
903 * into the list of expiring nodes with the ones to be
904 * removed first added to the front of the list. The
905 * insertion is O(n) but it is kept sorted for quick scans
906 * at expiration interval checks.
910 ipe->ipe_die = softc->ipf_ticks + IPF_TTLVAL(ipe->ipe_die);
911 for (n = softh->ipf_node_explist; n != NULL; n = n->ipe_dnext) {
912 if (ipe->ipe_die < n->ipe_die)
914 if (n->ipe_dnext == NULL) {
916 * We've got to the last node and everything
917 * wanted to be expired before this new node,
918 * so we have to tack it on the end...
921 ipe->ipe_pdnext = &n->ipe_dnext;
927 if (softh->ipf_node_explist == NULL) {
928 softh->ipf_node_explist = ipe;
929 ipe->ipe_pdnext = &softh->ipf_node_explist;
930 } else if (n != NULL) {
932 ipe->ipe_pdnext = n->ipe_pdnext;
933 n->ipe_pdnext = &ipe->ipe_dnext;
937 if (ipe->ipe_family == AF_INET) {
938 ipf_inet_mask_add(bits, &iph->iph_v4_masks);
941 else if (ipe->ipe_family == AF_INET6) {
942 ipf_inet6_mask_add(bits, &ipe->ipe_mask, &iph->iph_v6_masks);
946 switch (iph->iph_type & ~IPHASH_ANON)
948 case IPHASH_GROUPMAP :
949 ipe->ipe_ptr = ipf_group_add(softc, ipe->ipe_group, NULL,
950 iph->iph_flags, IPL_LOGIPF,
960 ipe->ipe_unit = iph->iph_unit;
961 softh->ipf_nhtnodes[ipe->ipe_unit + 1]++;
967 /* ------------------------------------------------------------------------ */
968 /* Function: ipf_htent_find */
969 /* Returns: int - 0 = success, else error */
970 /* Parameters: iph(I) - pointer to table to search */
971 /* ipeo(I) - pointer to entry to find */
973 /* While it isn't absolutely necessary to for the address and mask to be */
974 /* passed in through an iphtent_t structure, one is always present when it */
975 /* is time to call this function, so it is just more convenient. */
976 /* ------------------------------------------------------------------------ */
978 ipf_htent_find(iphtable_t *iph, iphtent_t *ipeo)
984 bcopy((char *)ipeo, (char *)&ipe, sizeof(ipe));
985 ipe.ipe_addr.i6[0] &= ipe.ipe_mask.i6[0];
986 ipe.ipe_addr.i6[1] &= ipe.ipe_mask.i6[1];
987 ipe.ipe_addr.i6[2] &= ipe.ipe_mask.i6[2];
988 ipe.ipe_addr.i6[3] &= ipe.ipe_mask.i6[3];
989 if (ipe.ipe_family == AF_INET) {
990 bits = count4bits(ipe.ipe_mask.in4_addr);
991 ipe.ipe_addr.i6[1] = 0;
992 ipe.ipe_addr.i6[2] = 0;
993 ipe.ipe_addr.i6[3] = 0;
994 ipe.ipe_mask.i6[1] = 0;
995 ipe.ipe_mask.i6[2] = 0;
996 ipe.ipe_mask.i6[3] = 0;
997 hv = IPE_V4_HASH_FN(ipe.ipe_addr.in4_addr,
998 ipe.ipe_mask.in4_addr, iph->iph_size);
1001 if (ipe.ipe_family == AF_INET6) {
1002 bits = count6bits(ipe.ipe_mask.i6);
1003 hv = IPE_V6_HASH_FN(ipe.ipe_addr.i6,
1004 ipe.ipe_mask.i6, iph->iph_size);
1009 for (ent = iph->iph_table[hv]; ent != NULL; ent = ent->ipe_hnext) {
1010 if (ent->ipe_family != ipe.ipe_family)
1012 if (IP6_NEQ(&ipe.ipe_addr, &ent->ipe_addr))
1014 if (IP6_NEQ(&ipe.ipe_mask, &ent->ipe_mask))
1023 /* ------------------------------------------------------------------------ */
1024 /* Function: ipf_iphmfindgroup */
1025 /* Returns: int - 0 = success, else error */
1026 /* Parameters: softc(I) - pointer to soft context main structure */
1030 /* Search a hash table for a matching entry and return the pointer stored */
1031 /* in it for use as the next group of rules to search. */
1033 /* This function is exposed becaues it is used in the group-map feature. */
1034 /* ------------------------------------------------------------------------ */
1036 ipf_iphmfindgroup(ipf_main_softc_t *softc, void *tptr, void *aptr)
1038 struct in_addr *addr;
1043 READ_ENTER(&softc->ipf_poolrw);
1047 ipe = ipf_iphmfind(iph, addr);
1049 rval = ipe->ipe_ptr;
1052 RWLOCK_EXIT(&softc->ipf_poolrw);
1057 /* ------------------------------------------------------------------------ */
1058 /* Function: ipf_iphmfindip */
1059 /* Returns: int - 0 == +ve match, -1 == error, 1 == -ve/no match */
1060 /* Parameters: softc(I) - pointer to soft context main structure */
1061 /* tptr(I) - pointer to the pool to search */
1062 /* ipversion(I) - IP protocol version (4 or 6) */
1063 /* aptr(I) - pointer to address information */
1064 /* bytes(I) - packet length */
1066 /* Search the hash table for a given address and return a search result. */
1067 /* ------------------------------------------------------------------------ */
1069 ipf_iphmfindip(ipf_main_softc_t *softc, void *tptr, int ipversion, void *aptr,
1072 struct in_addr *addr;
1077 if (tptr == NULL || aptr == NULL)
1083 READ_ENTER(&softc->ipf_poolrw);
1084 if (ipversion == 4) {
1085 ipe = ipf_iphmfind(iph, addr);
1087 } else if (ipversion == 6) {
1088 ipe = ipf_iphmfind6(iph, (i6addr_t *)addr);
1097 ipe->ipe_bytes += bytes;
1101 RWLOCK_EXIT(&softc->ipf_poolrw);
1106 /* ------------------------------------------------------------------------ */
1107 /* Function: ipf_iphmfindip */
1108 /* Parameters: iph(I) - pointer to hash table */
1109 /* addr(I) - pointer to IPv4 address */
1110 /* Locks: ipf_poolrw */
1112 /* ------------------------------------------------------------------------ */
1114 ipf_iphmfind(iphtable_t *iph, struct in_addr *addr)
1123 msk = iph->iph_v4_masks.imt4_active[i];
1124 ips = addr->s_addr & msk;
1125 hv = IPE_V4_HASH_FN(ips, msk, iph->iph_size);
1126 for (ipe = iph->iph_table[hv]; (ipe != NULL); ipe = ipe->ipe_hnext) {
1127 if ((ipe->ipe_family != AF_INET) ||
1128 (ipe->ipe_mask.in4_addr != msk) ||
1129 (ipe->ipe_addr.in4_addr != ips)) {
1137 if (i < iph->iph_v4_masks.imt4_max)
1144 /* ------------------------------------------------------------------------ */
1145 /* Function: ipf_htable_iter_next */
1146 /* Returns: int - 0 = success, else error */
1147 /* Parameters: softc(I) - pointer to soft context main structure */
1148 /* arg(I) - pointer to local context to use */
1152 /* ------------------------------------------------------------------------ */
1154 ipf_htable_iter_next(ipf_main_softc_t *softc, void *arg, ipftoken_t *token,
1155 ipflookupiter_t *ilp)
1157 ipf_htable_softc_t *softh = arg;
1158 iphtent_t *node, zn, *nextnode;
1159 iphtable_t *iph, zp, *nextiph;
1169 READ_ENTER(&softc->ipf_poolrw);
1171 switch (ilp->ili_otype)
1173 case IPFLOOKUPITER_LIST :
1174 iph = token->ipt_data;
1176 nextiph = softh->ipf_htables[(int)ilp->ili_unit + 1];
1178 nextiph = iph->iph_next;
1181 if (nextiph != NULL) {
1182 ATOMIC_INC(nextiph->iph_ref);
1183 token->ipt_data = nextiph;
1185 bzero((char *)&zp, sizeof(zp));
1187 token->ipt_data = NULL;
1189 hnext = nextiph->iph_next;
1192 case IPFLOOKUPITER_NODE :
1193 node = token->ipt_data;
1195 iph = ipf_htable_find(arg, ilp->ili_unit,
1201 nextnode = iph->iph_list;
1204 nextnode = node->ipe_next;
1207 if (nextnode != NULL) {
1208 ATOMIC_INC(nextnode->ipe_ref);
1209 token->ipt_data = nextnode;
1211 bzero((char *)&zn, sizeof(zn));
1213 token->ipt_data = NULL;
1215 hnext = nextnode->ipe_next;
1225 RWLOCK_EXIT(&softc->ipf_poolrw);
1229 switch (ilp->ili_otype)
1231 case IPFLOOKUPITER_LIST :
1232 err = COPYOUT(nextiph, ilp->ili_data, sizeof(*nextiph));
1238 WRITE_ENTER(&softc->ipf_poolrw);
1239 ipf_htable_deref(softc, softh, iph);
1240 RWLOCK_EXIT(&softc->ipf_poolrw);
1244 case IPFLOOKUPITER_NODE :
1245 err = COPYOUT(nextnode, ilp->ili_data, sizeof(*nextnode));
1251 WRITE_ENTER(&softc->ipf_poolrw);
1252 ipf_htent_deref(softc, node);
1253 RWLOCK_EXIT(&softc->ipf_poolrw);
1259 ipf_token_mark_complete(token);
1265 /* ------------------------------------------------------------------------ */
1266 /* Function: ipf_htable_iter_deref */
1267 /* Returns: int - 0 = success, else error */
1268 /* Parameters: softc(I) - pointer to soft context main structure */
1269 /* arg(I) - pointer to local context to use */
1270 /* otype(I) - which data structure type is being walked */
1271 /* unit(I) - ipfilter device to which we are working on */
1272 /* data(I) - pointer to old data structure */
1274 /* ------------------------------------------------------------------------ */
1276 ipf_htable_iter_deref(ipf_main_softc_t *softc, void *arg, int otype, int unit,
1283 if (unit < -1 || unit > IPL_LOGMAX)
1288 case IPFLOOKUPITER_LIST :
1289 ipf_htable_deref(softc, arg, (iphtable_t *)data);
1292 case IPFLOOKUPITER_NODE :
1293 ipf_htent_deref(arg, (iphtent_t *)data);
1304 /* ------------------------------------------------------------------------ */
1305 /* Function: ipf_iphmfind6 */
1306 /* Parameters: iph(I) - pointer to hash table */
1307 /* addr(I) - pointer to IPv6 address */
1308 /* Locks: ipf_poolrw */
1310 /* ------------------------------------------------------------------------ */
1312 ipf_iphmfind6(iphtable_t *iph, i6addr_t *addr)
1321 msk = iph->iph_v6_masks.imt6_active + i;
1322 ips.i6[0] = addr->i6[0] & msk->i6[0];
1323 ips.i6[1] = addr->i6[1] & msk->i6[1];
1324 ips.i6[2] = addr->i6[2] & msk->i6[2];
1325 ips.i6[3] = addr->i6[3] & msk->i6[3];
1326 hv = IPE_V6_HASH_FN(ips.i6, msk->i6, iph->iph_size);
1327 for (ipe = iph->iph_table[hv]; (ipe != NULL); ipe = ipe->ipe_next) {
1328 if ((ipe->ipe_family != AF_INET6) ||
1329 IP6_NEQ(&ipe->ipe_mask, msk) ||
1330 IP6_NEQ(&ipe->ipe_addr, &ips)) {
1338 if (i < iph->iph_v6_masks.imt6_max)
1347 ipf_htable_expire(ipf_main_softc_t *softc, void *arg)
1349 ipf_htable_softc_t *softh = arg;
1352 while ((n = softh->ipf_node_explist) != NULL) {
1353 if (n->ipe_die > softc->ipf_ticks)
1356 ipf_htent_remove(softc, softh, n->ipe_owner, n);
1363 /* ------------------------------------------------------------------------ */
1365 /* ------------------------------------------------------------------------ */
1367 ipf_htable_dump(ipf_main_softc_t *softc, void *arg)
1369 ipf_htable_softc_t *softh = arg;
1373 printf("List of configured hash tables\n");
1374 for (i = 0; i < IPL_LOGSIZE; i++)
1375 for (iph = softh->ipf_htables[i]; iph != NULL;
1376 iph = iph->iph_next)
1377 printhash(iph, bcopywrap, NULL, opts, NULL);