13b9b51feSCy Schubert 
23b9b51feSCy Schubert /*
33b9b51feSCy Schubert  * Copyright (C) 2012 by Darren Reed.
43b9b51feSCy Schubert  *
53b9b51feSCy Schubert  * See the IPFILTER.LICENCE file for details on licencing.
63b9b51feSCy Schubert  */
73b9b51feSCy Schubert #if defined(KERNEL) || defined(_KERNEL)
83b9b51feSCy Schubert # undef KERNEL
93b9b51feSCy Schubert # undef _KERNEL
103b9b51feSCy Schubert # define        KERNEL	1
113b9b51feSCy Schubert # define        _KERNEL	1
123b9b51feSCy Schubert #endif
133b9b51feSCy Schubert #include <sys/param.h>
143b9b51feSCy Schubert #include <sys/types.h>
153b9b51feSCy Schubert #include <sys/errno.h>
163b9b51feSCy Schubert #include <sys/time.h>
173b9b51feSCy Schubert #include <sys/file.h>
183b9b51feSCy Schubert #if !defined(_KERNEL)
193b9b51feSCy Schubert # include <stdlib.h>
203b9b51feSCy Schubert # include <string.h>
213b9b51feSCy Schubert # define _KERNEL
223b9b51feSCy Schubert # include <sys/uio.h>
233b9b51feSCy Schubert # undef _KERNEL
243b9b51feSCy Schubert #endif
253b9b51feSCy Schubert #include <sys/socket.h>
263b9b51feSCy Schubert #if defined(__FreeBSD__)
273b9b51feSCy Schubert # include <sys/malloc.h>
283b9b51feSCy Schubert #endif
293b9b51feSCy Schubert #if defined(__FreeBSD__)
303b9b51feSCy Schubert #  include <sys/cdefs.h>
313b9b51feSCy Schubert #  include <sys/proc.h>
323b9b51feSCy Schubert #endif
333b9b51feSCy Schubert #if !defined(__SVR4)
343b9b51feSCy Schubert # include <sys/mbuf.h>
353b9b51feSCy Schubert #endif
363b9b51feSCy Schubert #if defined(_KERNEL)
373b9b51feSCy Schubert # include <sys/systm.h>
383b9b51feSCy Schubert #else
393b9b51feSCy Schubert # include "ipf.h"
403b9b51feSCy Schubert #endif
413b9b51feSCy Schubert #include <netinet/in.h>
423b9b51feSCy Schubert #include <net/if.h>
433b9b51feSCy Schubert 
443b9b51feSCy Schubert #include "netinet/ip_compat.h"
453b9b51feSCy Schubert #include "netinet/ip_fil.h"
463b9b51feSCy Schubert #include "netinet/ip_lookup.h"
473b9b51feSCy Schubert #include "netinet/ip_htable.h"
483b9b51feSCy Schubert /* END OF INCLUDES */
493b9b51feSCy Schubert 
503b9b51feSCy Schubert 
513b9b51feSCy Schubert # ifdef USE_INET6
523b9b51feSCy Schubert static iphtent_t *ipf_iphmfind6(iphtable_t *, i6addr_t *);
533b9b51feSCy Schubert # endif
543b9b51feSCy Schubert static iphtent_t *ipf_iphmfind(iphtable_t *, struct in_addr *);
553b9b51feSCy Schubert static int ipf_iphmfindip(ipf_main_softc_t *, void *, int, void *, u_int);
563b9b51feSCy Schubert static int ipf_htable_clear(ipf_main_softc_t *, void *, iphtable_t *);
573b9b51feSCy Schubert static int ipf_htable_create(ipf_main_softc_t *, void *, iplookupop_t *);
583b9b51feSCy Schubert static int ipf_htable_deref(ipf_main_softc_t *, void *, void *);
593b9b51feSCy Schubert static int ipf_htable_destroy(ipf_main_softc_t *, void *, int, char *);
603b9b51feSCy Schubert static void *ipf_htable_exists(void *, int, char *);
613b9b51feSCy Schubert static size_t ipf_htable_flush(ipf_main_softc_t *, void *,
623b9b51feSCy Schubert 				    iplookupflush_t *);
633b9b51feSCy Schubert static void ipf_htable_free(void *, iphtable_t *);
643b9b51feSCy Schubert static int ipf_htable_iter_deref(ipf_main_softc_t *, void *, int,
653b9b51feSCy Schubert 				      int, void *);
663b9b51feSCy Schubert static int ipf_htable_iter_next(ipf_main_softc_t *, void *, ipftoken_t *,
673b9b51feSCy Schubert 				     ipflookupiter_t *);
683b9b51feSCy Schubert static int ipf_htable_node_add(ipf_main_softc_t *, void *,
693b9b51feSCy Schubert 				    iplookupop_t *, int);
703b9b51feSCy Schubert static int ipf_htable_node_del(ipf_main_softc_t *, void *,
713b9b51feSCy Schubert 				    iplookupop_t *, int);
723b9b51feSCy Schubert static int ipf_htable_remove(ipf_main_softc_t *, void *, iphtable_t *);
733b9b51feSCy Schubert static void *ipf_htable_soft_create(ipf_main_softc_t *);
743b9b51feSCy Schubert static void ipf_htable_soft_destroy(ipf_main_softc_t *, void *);
753b9b51feSCy Schubert static int ipf_htable_soft_init(ipf_main_softc_t *, void *);
763b9b51feSCy Schubert static void ipf_htable_soft_fini(ipf_main_softc_t *, void *);
773b9b51feSCy Schubert static int ipf_htable_stats_get(ipf_main_softc_t *, void *,
783b9b51feSCy Schubert 				     iplookupop_t *);
793b9b51feSCy Schubert static int ipf_htable_table_add(ipf_main_softc_t *, void *,
803b9b51feSCy Schubert 				     iplookupop_t *);
813b9b51feSCy Schubert static int ipf_htable_table_del(ipf_main_softc_t *, void *,
823b9b51feSCy Schubert 				     iplookupop_t *);
833b9b51feSCy Schubert static int ipf_htent_deref(void *, iphtent_t *);
843b9b51feSCy Schubert static iphtent_t *ipf_htent_find(iphtable_t *, iphtent_t *);
853b9b51feSCy Schubert static int ipf_htent_insert(ipf_main_softc_t *, void *, iphtable_t *,
863b9b51feSCy Schubert 				 iphtent_t *);
873b9b51feSCy Schubert static int ipf_htent_remove(ipf_main_softc_t *, void *, iphtable_t *,
883b9b51feSCy Schubert 				 iphtent_t *);
893b9b51feSCy Schubert static void *ipf_htable_select_add_ref(void *, int, char *);
903b9b51feSCy Schubert static void ipf_htable_expire(ipf_main_softc_t *, void *);
913b9b51feSCy Schubert 
923b9b51feSCy Schubert 
933b9b51feSCy Schubert typedef struct ipf_htable_softc_s {
943b9b51feSCy Schubert 	u_long		ipht_nomem[LOOKUP_POOL_SZ];
953b9b51feSCy Schubert 	u_long		ipf_nhtables[LOOKUP_POOL_SZ];
963b9b51feSCy Schubert 	u_long		ipf_nhtnodes[LOOKUP_POOL_SZ];
973b9b51feSCy Schubert 	iphtable_t	*ipf_htables[LOOKUP_POOL_SZ];
983b9b51feSCy Schubert 	iphtent_t	*ipf_node_explist;
993b9b51feSCy Schubert } ipf_htable_softc_t;
1003b9b51feSCy Schubert 
1013b9b51feSCy Schubert ipf_lookup_t ipf_htable_backend = {
1023b9b51feSCy Schubert 	IPLT_HASH,
1033b9b51feSCy Schubert 	ipf_htable_soft_create,
1043b9b51feSCy Schubert 	ipf_htable_soft_destroy,
1053b9b51feSCy Schubert 	ipf_htable_soft_init,
1063b9b51feSCy Schubert 	ipf_htable_soft_fini,
1073b9b51feSCy Schubert 	ipf_iphmfindip,
1083b9b51feSCy Schubert 	ipf_htable_flush,
1093b9b51feSCy Schubert 	ipf_htable_iter_deref,
1103b9b51feSCy Schubert 	ipf_htable_iter_next,
1113b9b51feSCy Schubert 	ipf_htable_node_add,
1123b9b51feSCy Schubert 	ipf_htable_node_del,
1133b9b51feSCy Schubert 	ipf_htable_stats_get,
1143b9b51feSCy Schubert 	ipf_htable_table_add,
1153b9b51feSCy Schubert 	ipf_htable_table_del,
1163b9b51feSCy Schubert 	ipf_htable_deref,
1173b9b51feSCy Schubert 	ipf_htable_exists,
1183b9b51feSCy Schubert 	ipf_htable_select_add_ref,
1193b9b51feSCy Schubert 	NULL,
1203b9b51feSCy Schubert 	ipf_htable_expire,
1213b9b51feSCy Schubert 	NULL
1223b9b51feSCy Schubert };
1233b9b51feSCy Schubert 
1243b9b51feSCy Schubert 
1253b9b51feSCy Schubert /* ------------------------------------------------------------------------ */
1263b9b51feSCy Schubert /* Function:    ipf_htable_soft_create                                      */
1273b9b51feSCy Schubert /* Returns:     void *   - NULL = failure, else pointer to local context    */
1283b9b51feSCy Schubert /* Parameters:  softc(I) - pointer to soft context main structure           */
1293b9b51feSCy Schubert /*                                                                          */
1303b9b51feSCy Schubert /* Initialise the routing table data structures where required.             */
1313b9b51feSCy Schubert /* ------------------------------------------------------------------------ */
1323b9b51feSCy Schubert static void *
ipf_htable_soft_create(ipf_main_softc_t * softc)133064a5a95SCy Schubert ipf_htable_soft_create(ipf_main_softc_t *softc)
1343b9b51feSCy Schubert {
1353b9b51feSCy Schubert 	ipf_htable_softc_t *softh;
1363b9b51feSCy Schubert 
1373b9b51feSCy Schubert 	KMALLOC(softh, ipf_htable_softc_t *);
1383b9b51feSCy Schubert 	if (softh == NULL) {
1393b9b51feSCy Schubert 		IPFERROR(30026);
1408c82b374SCy Schubert 		return (NULL);
1413b9b51feSCy Schubert 	}
1423b9b51feSCy Schubert 
1433b9b51feSCy Schubert 	bzero((char *)softh, sizeof(*softh));
1443b9b51feSCy Schubert 
1458c82b374SCy Schubert 	return (softh);
1463b9b51feSCy Schubert }
1473b9b51feSCy Schubert 
1483b9b51feSCy Schubert 
1493b9b51feSCy Schubert /* ------------------------------------------------------------------------ */
1503b9b51feSCy Schubert /* Function:    ipf_htable_soft_destroy                                     */
1513b9b51feSCy Schubert /* Returns:     Nil                                                         */
1523b9b51feSCy Schubert /* Parameters:  softc(I) - pointer to soft context main structure           */
1533b9b51feSCy Schubert /*              arg(I)   - pointer to local context to use                  */
1543b9b51feSCy Schubert /*                                                                          */
1553b9b51feSCy Schubert /* Clean up the pool by free'ing the radix tree associated with it and free */
1563b9b51feSCy Schubert /* up the pool context too.                                                 */
1573b9b51feSCy Schubert /* ------------------------------------------------------------------------ */
1583b9b51feSCy Schubert static void
ipf_htable_soft_destroy(ipf_main_softc_t * softc,void * arg)159064a5a95SCy Schubert ipf_htable_soft_destroy(ipf_main_softc_t *softc, void *arg)
1603b9b51feSCy Schubert {
1613b9b51feSCy Schubert 	ipf_htable_softc_t *softh = arg;
1623b9b51feSCy Schubert 
1633b9b51feSCy Schubert 	KFREE(softh);
1643b9b51feSCy Schubert }
1653b9b51feSCy Schubert 
1663b9b51feSCy Schubert 
1673b9b51feSCy Schubert /* ------------------------------------------------------------------------ */
1683b9b51feSCy Schubert /* Function:    ipf_htable_soft_init                                        */
1693b9b51feSCy Schubert /* Returns:     int     - 0 = success, else error                           */
1703b9b51feSCy Schubert /* Parameters:  softc(I) - pointer to soft context main structure           */
1713b9b51feSCy Schubert /*              arg(I)   - pointer to local context to use                  */
1723b9b51feSCy Schubert /*                                                                          */
1733b9b51feSCy Schubert /* Initialise the hash table ready for use.                                 */
1743b9b51feSCy Schubert /* ------------------------------------------------------------------------ */
1753b9b51feSCy Schubert static int
ipf_htable_soft_init(ipf_main_softc_t * softc,void * arg)176ec6b2822SMateusz Guzik ipf_htable_soft_init(ipf_main_softc_t *softc, void *arg)
1773b9b51feSCy Schubert {
1783b9b51feSCy Schubert 	ipf_htable_softc_t *softh = arg;
1793b9b51feSCy Schubert 
1803b9b51feSCy Schubert 	bzero((char *)softh, sizeof(*softh));
1813b9b51feSCy Schubert 
1828c82b374SCy Schubert 	return (0);
1833b9b51feSCy Schubert }
1843b9b51feSCy Schubert 
1853b9b51feSCy Schubert 
1863b9b51feSCy Schubert /* ------------------------------------------------------------------------ */
1873b9b51feSCy Schubert /* Function:    ipf_htable_soft_fini                                        */
1883b9b51feSCy Schubert /* Returns:     Nil                                                         */
1893b9b51feSCy Schubert /* Parameters:  softc(I) - pointer to soft context main structure           */
1903b9b51feSCy Schubert /*              arg(I)   - pointer to local context to use                  */
1913b9b51feSCy Schubert /* Locks:       WRITE(ipf_global)                                           */
1923b9b51feSCy Schubert /*                                                                          */
1933b9b51feSCy Schubert /* Clean up all the pool data structures allocated and call the cleanup     */
1943b9b51feSCy Schubert /* function for the radix tree that supports the pools. ipf_pool_destroy is */
1953b9b51feSCy Schubert /* used to delete the pools one by one to ensure they're properly freed up. */
1963b9b51feSCy Schubert /* ------------------------------------------------------------------------ */
1973b9b51feSCy Schubert static void
ipf_htable_soft_fini(ipf_main_softc_t * softc,void * arg)198064a5a95SCy Schubert ipf_htable_soft_fini(ipf_main_softc_t *softc, void *arg)
1993b9b51feSCy Schubert {
2003b9b51feSCy Schubert 	iplookupflush_t fop;
2013b9b51feSCy Schubert 
2023b9b51feSCy Schubert 	fop.iplf_type = IPLT_HASH;
2033b9b51feSCy Schubert 	fop.iplf_unit = IPL_LOGALL;
2043b9b51feSCy Schubert 	fop.iplf_arg = 0;
2053b9b51feSCy Schubert 	fop.iplf_count = 0;
2063b9b51feSCy Schubert 	*fop.iplf_name = '\0';
2073b9b51feSCy Schubert 	ipf_htable_flush(softc, arg, &fop);
2083b9b51feSCy Schubert }
2093b9b51feSCy Schubert 
2103b9b51feSCy Schubert 
2113b9b51feSCy Schubert /* ------------------------------------------------------------------------ */
2123b9b51feSCy Schubert /* Function:    ipf_htable_stats_get                                        */
2133b9b51feSCy Schubert /* Returns:     int - 0 = success, else error                               */
2143b9b51feSCy Schubert /* Parameters:  softc(I) - pointer to soft context main structure           */
2153b9b51feSCy Schubert /*              arg(I)   - pointer to local context to use                  */
2163b9b51feSCy Schubert /*              op(I)    - pointer to lookup operation data                 */
2173b9b51feSCy Schubert /*                                                                          */
2183b9b51feSCy Schubert /* Copy the relevant statistics out of internal structures and into the     */
2193b9b51feSCy Schubert /* structure used to export statistics.                                     */
2203b9b51feSCy Schubert /* ------------------------------------------------------------------------ */
2213b9b51feSCy Schubert static int
ipf_htable_stats_get(ipf_main_softc_t * softc,void * arg,iplookupop_t * op)222064a5a95SCy Schubert ipf_htable_stats_get(ipf_main_softc_t *softc, void *arg, iplookupop_t *op)
2233b9b51feSCy Schubert {
2243b9b51feSCy Schubert 	ipf_htable_softc_t *softh = arg;
2253b9b51feSCy Schubert 	iphtstat_t stats;
2263b9b51feSCy Schubert 	int err;
2273b9b51feSCy Schubert 
2283b9b51feSCy Schubert 	if (op->iplo_size != sizeof(stats)) {
2293b9b51feSCy Schubert 		IPFERROR(30001);
2308c82b374SCy Schubert 		return (EINVAL);
2313b9b51feSCy Schubert 	}
2323b9b51feSCy Schubert 
2333b9b51feSCy Schubert 	stats.iphs_tables = softh->ipf_htables[op->iplo_unit + 1];
2343b9b51feSCy Schubert 	stats.iphs_numtables = softh->ipf_nhtables[op->iplo_unit + 1];
2353b9b51feSCy Schubert 	stats.iphs_numnodes = softh->ipf_nhtnodes[op->iplo_unit + 1];
2363b9b51feSCy Schubert 	stats.iphs_nomem = softh->ipht_nomem[op->iplo_unit + 1];
2373b9b51feSCy Schubert 
2383b9b51feSCy Schubert 	err = COPYOUT(&stats, op->iplo_struct, sizeof(stats));
2393b9b51feSCy Schubert 	if (err != 0) {
2403b9b51feSCy Schubert 		IPFERROR(30013);
2418c82b374SCy Schubert 		return (EFAULT);
2423b9b51feSCy Schubert 	}
2438c82b374SCy Schubert 	return (0);
2443b9b51feSCy Schubert 
2453b9b51feSCy Schubert }
2463b9b51feSCy Schubert 
2473b9b51feSCy Schubert 
2483b9b51feSCy Schubert /* ------------------------------------------------------------------------ */
2493b9b51feSCy Schubert /* Function:    ipf_htable_create                                           */
2503b9b51feSCy Schubert /* Returns:     int - 0 = success, else error                               */
2513b9b51feSCy Schubert /* Parameters:  softc(I) - pointer to soft context main structure           */
2523b9b51feSCy Schubert /*              arg(I)   - pointer to local context to use                  */
2533b9b51feSCy Schubert /*              op(I)    - pointer to lookup operation data                 */
2543b9b51feSCy Schubert /*                                                                          */
2553b9b51feSCy Schubert /* Create a new hash table using the template passed.                       */
2563b9b51feSCy Schubert /* ------------------------------------------------------------------------ */
2573b9b51feSCy Schubert static int
ipf_htable_create(ipf_main_softc_t * softc,void * arg,iplookupop_t * op)258064a5a95SCy Schubert ipf_htable_create(ipf_main_softc_t *softc, void *arg, iplookupop_t *op)
2593b9b51feSCy Schubert {
2603b9b51feSCy Schubert 	ipf_htable_softc_t *softh = arg;
2613b9b51feSCy Schubert 	iphtable_t htab, *iph, *oiph;
2623b9b51feSCy Schubert 	char name[FR_GROUPLEN];
2633b9b51feSCy Schubert 	int err, i, unit;
2643b9b51feSCy Schubert 
2653b9b51feSCy Schubert 	if (op->iplo_size != sizeof(htab)) {
2663b9b51feSCy Schubert 		IPFERROR(30024);
2678c82b374SCy Schubert 		return (EINVAL);
2683b9b51feSCy Schubert 	}
2693b9b51feSCy Schubert 	err = COPYIN(op->iplo_struct, &htab, sizeof(htab));
2703b9b51feSCy Schubert 	if (err != 0) {
2713b9b51feSCy Schubert 		IPFERROR(30003);
2728c82b374SCy Schubert 		return (EFAULT);
2733b9b51feSCy Schubert 	}
2743b9b51feSCy Schubert 
2753b9b51feSCy Schubert 	unit = op->iplo_unit;
2763b9b51feSCy Schubert 	if (htab.iph_unit != unit) {
2773b9b51feSCy Schubert 		IPFERROR(30005);
2788c82b374SCy Schubert 		return (EINVAL);
2793b9b51feSCy Schubert 	}
2803b9b51feSCy Schubert 	if (htab.iph_size < 1) {
2813b9b51feSCy Schubert 		IPFERROR(30025);
2828c82b374SCy Schubert 		return (EINVAL);
2833b9b51feSCy Schubert 	}
2843b9b51feSCy Schubert 
2853b9b51feSCy Schubert 
2863b9b51feSCy Schubert 	if ((op->iplo_arg & IPHASH_ANON) == 0) {
2873b9b51feSCy Schubert 		iph = ipf_htable_exists(softh, unit, op->iplo_name);
2883b9b51feSCy Schubert 		if (iph != NULL) {
2893b9b51feSCy Schubert 			if ((iph->iph_flags & IPHASH_DELETE) == 0) {
2903b9b51feSCy Schubert 				IPFERROR(30004);
2918c82b374SCy Schubert 				return (EEXIST);
2923b9b51feSCy Schubert 			}
2933b9b51feSCy Schubert 			iph->iph_flags &= ~IPHASH_DELETE;
2943b9b51feSCy Schubert 			iph->iph_ref++;
2958c82b374SCy Schubert 			return (0);
2963b9b51feSCy Schubert 		}
2973b9b51feSCy Schubert 	}
2983b9b51feSCy Schubert 
2993b9b51feSCy Schubert 	KMALLOC(iph, iphtable_t *);
3003b9b51feSCy Schubert 	if (iph == NULL) {
3013b9b51feSCy Schubert 		softh->ipht_nomem[op->iplo_unit + 1]++;
3023b9b51feSCy Schubert 		IPFERROR(30002);
3038c82b374SCy Schubert 		return (ENOMEM);
3043b9b51feSCy Schubert 	}
3053b9b51feSCy Schubert 	*iph = htab;
3063b9b51feSCy Schubert 
3073b9b51feSCy Schubert 	if ((op->iplo_arg & IPHASH_ANON) != 0) {
3083b9b51feSCy Schubert 		i = IPHASH_ANON;
3093b9b51feSCy Schubert 		do {
3103b9b51feSCy Schubert 			i++;
3113b9b51feSCy Schubert 			(void)snprintf(name, sizeof(name), "%u", i);
3123b9b51feSCy Schubert 			for (oiph = softh->ipf_htables[unit + 1]; oiph != NULL;
3133b9b51feSCy Schubert 			     oiph = oiph->iph_next)
3143b9b51feSCy Schubert 				if (strncmp(oiph->iph_name, name,
3153b9b51feSCy Schubert 					    sizeof(oiph->iph_name)) == 0)
3163b9b51feSCy Schubert 					break;
3173b9b51feSCy Schubert 		} while (oiph != NULL);
3183b9b51feSCy Schubert 
3193b9b51feSCy Schubert 		(void)strncpy(iph->iph_name, name, sizeof(iph->iph_name));
3203b9b51feSCy Schubert 		(void)strncpy(op->iplo_name, name, sizeof(op->iplo_name));
3213b9b51feSCy Schubert 		iph->iph_type |= IPHASH_ANON;
3223b9b51feSCy Schubert 	} else {
3233b9b51feSCy Schubert 		(void)strncpy(iph->iph_name, op->iplo_name,
3243b9b51feSCy Schubert 			      sizeof(iph->iph_name));
3253b9b51feSCy Schubert 		iph->iph_name[sizeof(iph->iph_name) - 1] = '\0';
3263b9b51feSCy Schubert 	}
3273b9b51feSCy Schubert 
3283b9b51feSCy Schubert 	KMALLOCS(iph->iph_table, iphtent_t **,
3293b9b51feSCy Schubert 		 iph->iph_size * sizeof(*iph->iph_table));
3303b9b51feSCy Schubert 	if (iph->iph_table == NULL) {
3313b9b51feSCy Schubert 		KFREE(iph);
3323b9b51feSCy Schubert 		softh->ipht_nomem[unit + 1]++;
3333b9b51feSCy Schubert 		IPFERROR(30006);
3348c82b374SCy Schubert 		return (ENOMEM);
3353b9b51feSCy Schubert 	}
3363b9b51feSCy Schubert 
3373b9b51feSCy Schubert 	bzero((char *)iph->iph_table, iph->iph_size * sizeof(*iph->iph_table));
3383b9b51feSCy Schubert 	iph->iph_maskset[0] = 0;
3393b9b51feSCy Schubert 	iph->iph_maskset[1] = 0;
3403b9b51feSCy Schubert 	iph->iph_maskset[2] = 0;
3413b9b51feSCy Schubert 	iph->iph_maskset[3] = 0;
3423b9b51feSCy Schubert 
3433b9b51feSCy Schubert 	iph->iph_ref = 1;
3443b9b51feSCy Schubert 	iph->iph_list = NULL;
3453b9b51feSCy Schubert 	iph->iph_tail = &iph->iph_list;
3463b9b51feSCy Schubert 	iph->iph_next = softh->ipf_htables[unit + 1];
3473b9b51feSCy Schubert 	iph->iph_pnext = &softh->ipf_htables[unit + 1];
3483b9b51feSCy Schubert 	if (softh->ipf_htables[unit + 1] != NULL)
3493b9b51feSCy Schubert 		softh->ipf_htables[unit + 1]->iph_pnext = &iph->iph_next;
3503b9b51feSCy Schubert 	softh->ipf_htables[unit + 1] = iph;
3513b9b51feSCy Schubert 
3523b9b51feSCy Schubert 	softh->ipf_nhtables[unit + 1]++;
3533b9b51feSCy Schubert 
3548c82b374SCy Schubert 	return (0);
3553b9b51feSCy Schubert }
3563b9b51feSCy Schubert 
3573b9b51feSCy Schubert 
3583b9b51feSCy Schubert /* ------------------------------------------------------------------------ */
3593b9b51feSCy Schubert /* Function:    ipf_htable_table_del                                        */
3603b9b51feSCy Schubert /* Returns:     int      - 0 = success, else error                          */
3613b9b51feSCy Schubert /* Parameters:  softc(I) - pointer to soft context main structure           */
3623b9b51feSCy Schubert /*              arg(I)   - pointer to local context to use                  */
3633b9b51feSCy Schubert /*              op(I)    - pointer to lookup operation data                 */
3643b9b51feSCy Schubert /*                                                                          */
3653b9b51feSCy Schubert /* ------------------------------------------------------------------------ */
3663b9b51feSCy Schubert static int
ipf_htable_table_del(ipf_main_softc_t * softc,void * arg,iplookupop_t * op)367064a5a95SCy Schubert ipf_htable_table_del(ipf_main_softc_t *softc, void *arg, iplookupop_t *op)
3683b9b51feSCy Schubert {
3698c82b374SCy Schubert 	return (ipf_htable_destroy(softc, arg, op->iplo_unit, op->iplo_name));
3703b9b51feSCy Schubert }
3713b9b51feSCy Schubert 
3723b9b51feSCy Schubert 
3733b9b51feSCy Schubert /* ------------------------------------------------------------------------ */
3743b9b51feSCy Schubert /* Function:    ipf_htable_destroy                                          */
3753b9b51feSCy Schubert /* Returns:     int      - 0 = success, else error                          */
3763b9b51feSCy Schubert /* Parameters:  softc(I) - pointer to soft context main structure           */
3773b9b51feSCy Schubert /*              arg(I)   - pointer to local context to use                  */
3783b9b51feSCy Schubert /*              op(I)    - pointer to lookup operation data                 */
3793b9b51feSCy Schubert /*                                                                          */
3803b9b51feSCy Schubert /* Find the hash table that belongs to the relevant part of ipfilter with a */
3813b9b51feSCy Schubert /* matching name and attempt to destroy it.  If it is in use, empty it out  */
3823b9b51feSCy Schubert /* and mark it for deletion so that when all the references disappear, it   */
3833b9b51feSCy Schubert /* can be removed.                                                          */
3843b9b51feSCy Schubert /* ------------------------------------------------------------------------ */
3853b9b51feSCy Schubert static int
ipf_htable_destroy(ipf_main_softc_t * softc,void * arg,int unit,char * name)386064a5a95SCy Schubert ipf_htable_destroy(ipf_main_softc_t *softc, void *arg, int unit, char *name)
3873b9b51feSCy Schubert {
3883b9b51feSCy Schubert 	iphtable_t *iph;
3893b9b51feSCy Schubert 
3903b9b51feSCy Schubert 	iph = ipf_htable_find(arg, unit, name);
3913b9b51feSCy Schubert 	if (iph == NULL) {
3923b9b51feSCy Schubert 		IPFERROR(30007);
3938c82b374SCy Schubert 		return (ESRCH);
3943b9b51feSCy Schubert 	}
3953b9b51feSCy Schubert 
3963b9b51feSCy Schubert 	if (iph->iph_unit != unit) {
3973b9b51feSCy Schubert 		IPFERROR(30008);
3988c82b374SCy Schubert 		return (EINVAL);
3993b9b51feSCy Schubert 	}
4003b9b51feSCy Schubert 
4013b9b51feSCy Schubert 	if (iph->iph_ref != 0) {
4023b9b51feSCy Schubert 		ipf_htable_clear(softc, arg, iph);
4033b9b51feSCy Schubert 		iph->iph_flags |= IPHASH_DELETE;
4048c82b374SCy Schubert 		return (0);
4053b9b51feSCy Schubert 	}
4063b9b51feSCy Schubert 
4073b9b51feSCy Schubert 	ipf_htable_remove(softc, arg, iph);
4083b9b51feSCy Schubert 
4098c82b374SCy Schubert 	return (0);
4103b9b51feSCy Schubert }
4113b9b51feSCy Schubert 
4123b9b51feSCy Schubert 
4133b9b51feSCy Schubert /* ------------------------------------------------------------------------ */
4143b9b51feSCy Schubert /* Function:    ipf_htable_clear                                            */
4153b9b51feSCy Schubert /* Returns:     int      - 0 = success, else error                          */
4163b9b51feSCy Schubert /* Parameters:  softc(I) - pointer to soft context main structure           */
4173b9b51feSCy Schubert /*              arg(I)   - pointer to local context to use                  */
4183b9b51feSCy Schubert /*              iph(I)   - pointer to hash table to destroy                 */
4193b9b51feSCy Schubert /*                                                                          */
4203b9b51feSCy Schubert /* Clean out the hash table by walking the list of entries and removing     */
4213b9b51feSCy Schubert /* each one, one by one.                                                    */
4223b9b51feSCy Schubert /* ------------------------------------------------------------------------ */
4233b9b51feSCy Schubert static int
ipf_htable_clear(ipf_main_softc_t * softc,void * arg,iphtable_t * iph)424064a5a95SCy Schubert ipf_htable_clear(ipf_main_softc_t *softc, void *arg, iphtable_t *iph)
4253b9b51feSCy Schubert {
4263b9b51feSCy Schubert 	iphtent_t *ipe;
4273b9b51feSCy Schubert 
4283b9b51feSCy Schubert 	while ((ipe = iph->iph_list) != NULL)
4293b9b51feSCy Schubert 		if (ipf_htent_remove(softc, arg, iph, ipe) != 0)
4308c82b374SCy Schubert 			return (1);
4318c82b374SCy Schubert 	return (0);
4323b9b51feSCy Schubert }
4333b9b51feSCy Schubert 
4343b9b51feSCy Schubert 
4353b9b51feSCy Schubert /* ------------------------------------------------------------------------ */
4363b9b51feSCy Schubert /* Function:    ipf_htable_free                                             */
4373b9b51feSCy Schubert /* Returns:     Nil                                                         */
4383b9b51feSCy Schubert /* Parameters:  arg(I) - pointer to local context to use                    */
4393b9b51feSCy Schubert /*              iph(I) - pointer to hash table to destroy                   */
4403b9b51feSCy Schubert /*                                                                          */
4413b9b51feSCy Schubert /* ------------------------------------------------------------------------ */
4423b9b51feSCy Schubert static void
ipf_htable_free(void * arg,iphtable_t * iph)443064a5a95SCy Schubert ipf_htable_free(void *arg, iphtable_t *iph)
4443b9b51feSCy Schubert {
4453b9b51feSCy Schubert 	ipf_htable_softc_t *softh = arg;
4463b9b51feSCy Schubert 
4473b9b51feSCy Schubert 	if (iph->iph_next != NULL)
4483b9b51feSCy Schubert 		iph->iph_next->iph_pnext = iph->iph_pnext;
4493b9b51feSCy Schubert 	if (iph->iph_pnext != NULL)
4503b9b51feSCy Schubert 		*iph->iph_pnext = iph->iph_next;
4513b9b51feSCy Schubert 	iph->iph_pnext = NULL;
4523b9b51feSCy Schubert 	iph->iph_next = NULL;
4533b9b51feSCy Schubert 
4543b9b51feSCy Schubert 	softh->ipf_nhtables[iph->iph_unit + 1]--;
4553b9b51feSCy Schubert 
4563b9b51feSCy Schubert 	KFREES(iph->iph_table, iph->iph_size * sizeof(*iph->iph_table));
4573b9b51feSCy Schubert 	KFREE(iph);
4583b9b51feSCy Schubert }
4593b9b51feSCy Schubert 
4603b9b51feSCy Schubert 
4613b9b51feSCy Schubert /* ------------------------------------------------------------------------ */
4623b9b51feSCy Schubert /* Function:    ipf_htable_remove                                           */
4633b9b51feSCy Schubert /* Returns:     int      - 0 = success, else error                          */
4643b9b51feSCy Schubert /* Parameters:  softc(I) - pointer to soft context main structure           */
4653b9b51feSCy Schubert /*              arg(I)   - pointer to local context to use                  */
4663b9b51feSCy Schubert /*              iph(I)   - pointer to hash table to destroy                 */
4673b9b51feSCy Schubert /*                                                                          */
4683b9b51feSCy Schubert /* It is necessary to unlink here as well as free (called by deref) so that */
4693b9b51feSCy Schubert /* the while loop in ipf_htable_flush() functions properly.                 */
4703b9b51feSCy Schubert /* ------------------------------------------------------------------------ */
4713b9b51feSCy Schubert static int
ipf_htable_remove(ipf_main_softc_t * softc,void * arg,iphtable_t * iph)472064a5a95SCy Schubert ipf_htable_remove(ipf_main_softc_t *softc, void *arg, iphtable_t *iph)
4733b9b51feSCy Schubert {
4743b9b51feSCy Schubert 
4753b9b51feSCy Schubert 	if (ipf_htable_clear(softc, arg, iph) != 0)
4768c82b374SCy Schubert 		return (1);
4773b9b51feSCy Schubert 
4783b9b51feSCy Schubert 	if (iph->iph_pnext != NULL)
4793b9b51feSCy Schubert 		*iph->iph_pnext = iph->iph_next;
4803b9b51feSCy Schubert 	if (iph->iph_next != NULL)
4813b9b51feSCy Schubert 		iph->iph_next->iph_pnext = iph->iph_pnext;
4823b9b51feSCy Schubert 	iph->iph_pnext = NULL;
4833b9b51feSCy Schubert 	iph->iph_next = NULL;
4843b9b51feSCy Schubert 
4858c82b374SCy Schubert 	return (ipf_htable_deref(softc, arg, iph));
4863b9b51feSCy Schubert }
4873b9b51feSCy Schubert 
4883b9b51feSCy Schubert 
4893b9b51feSCy Schubert /* ------------------------------------------------------------------------ */
4903b9b51feSCy Schubert /* Function:    ipf_htable_node_del                                         */
4913b9b51feSCy Schubert /* Returns:     int      - 0 = success, else error                          */
4923b9b51feSCy Schubert /* Parameters:  softc(I) - pointer to soft context main structure           */
4933b9b51feSCy Schubert /*              arg(I)   - pointer to local context to use                  */
4943b9b51feSCy Schubert /*              op(I)    - pointer to lookup operation data                 */
4953b9b51feSCy Schubert /*              uid(I)   - real uid of process doing operation              */
4963b9b51feSCy Schubert /*                                                                          */
4973b9b51feSCy Schubert /* ------------------------------------------------------------------------ */
4983b9b51feSCy Schubert static int
ipf_htable_node_del(ipf_main_softc_t * softc,void * arg,iplookupop_t * op,int uid)499064a5a95SCy Schubert ipf_htable_node_del(ipf_main_softc_t *softc, void *arg, iplookupop_t *op,
500064a5a95SCy Schubert 	int uid)
5013b9b51feSCy Schubert {
5023b9b51feSCy Schubert 	iphtable_t *iph;
5033b9b51feSCy Schubert 	iphtent_t hte, *ent;
5043b9b51feSCy Schubert 	int err;
5053b9b51feSCy Schubert 
5063b9b51feSCy Schubert 	if (op->iplo_size != sizeof(hte)) {
5073b9b51feSCy Schubert 		IPFERROR(30014);
5088c82b374SCy Schubert 		return (EINVAL);
5093b9b51feSCy Schubert 	}
5103b9b51feSCy Schubert 
5113b9b51feSCy Schubert 	err = COPYIN(op->iplo_struct, &hte, sizeof(hte));
5123b9b51feSCy Schubert 	if (err != 0) {
5133b9b51feSCy Schubert 		IPFERROR(30015);
5148c82b374SCy Schubert 		return (EFAULT);
5153b9b51feSCy Schubert 	}
5163b9b51feSCy Schubert 
5173b9b51feSCy Schubert 	iph = ipf_htable_find(arg, op->iplo_unit, op->iplo_name);
5183b9b51feSCy Schubert 	if (iph == NULL) {
5193b9b51feSCy Schubert 		IPFERROR(30016);
5208c82b374SCy Schubert 		return (ESRCH);
5213b9b51feSCy Schubert 	}
5223b9b51feSCy Schubert 
5233b9b51feSCy Schubert 	ent = ipf_htent_find(iph, &hte);
5243b9b51feSCy Schubert 	if (ent == NULL) {
5253b9b51feSCy Schubert 		IPFERROR(30022);
5268c82b374SCy Schubert 		return (ESRCH);
5273b9b51feSCy Schubert 	}
5283b9b51feSCy Schubert 
5293b9b51feSCy Schubert 	if ((uid != 0) && (ent->ipe_uid != uid)) {
5303b9b51feSCy Schubert 		IPFERROR(30023);
5318c82b374SCy Schubert 		return (EACCES);
5323b9b51feSCy Schubert 	}
5333b9b51feSCy Schubert 
5343b9b51feSCy Schubert 	err = ipf_htent_remove(softc, arg, iph, ent);
5353b9b51feSCy Schubert 
5368c82b374SCy Schubert 	return (err);
5373b9b51feSCy Schubert }
5383b9b51feSCy Schubert 
5393b9b51feSCy Schubert 
5403b9b51feSCy Schubert /* ------------------------------------------------------------------------ */
5413b9b51feSCy Schubert /* Function:    ipf_htable_node_del                                         */
5423b9b51feSCy Schubert /* Returns:     int      - 0 = success, else error                          */
5433b9b51feSCy Schubert /* Parameters:  softc(I) - pointer to soft context main structure           */
5443b9b51feSCy Schubert /*              arg(I)   - pointer to local context to use                  */
5453b9b51feSCy Schubert /*              op(I)    - pointer to lookup operation data                 */
5463b9b51feSCy Schubert /*                                                                          */
5473b9b51feSCy Schubert /* ------------------------------------------------------------------------ */
5483b9b51feSCy Schubert static int
ipf_htable_table_add(ipf_main_softc_t * softc,void * arg,iplookupop_t * op)549064a5a95SCy Schubert ipf_htable_table_add(ipf_main_softc_t *softc, void *arg, iplookupop_t *op)
5503b9b51feSCy Schubert {
5513b9b51feSCy Schubert 	int err;
5523b9b51feSCy Schubert 
5533b9b51feSCy Schubert 	if (ipf_htable_find(arg, op->iplo_unit, op->iplo_name) != NULL) {
5543b9b51feSCy Schubert 		IPFERROR(30017);
5553b9b51feSCy Schubert 		err = EEXIST;
5563b9b51feSCy Schubert 	} else {
5573b9b51feSCy Schubert 		err = ipf_htable_create(softc, arg, op);
5583b9b51feSCy Schubert 	}
5593b9b51feSCy Schubert 
5608c82b374SCy Schubert 	return (err);
5613b9b51feSCy Schubert }
5623b9b51feSCy Schubert 
5633b9b51feSCy Schubert 
5643b9b51feSCy Schubert /* ------------------------------------------------------------------------ */
5653b9b51feSCy Schubert /* Function:    ipf_htent_remove                                            */
5663b9b51feSCy Schubert /* Returns:     int      - 0 = success, else error                          */
5673b9b51feSCy Schubert /* Parameters:  softc(I) - pointer to soft context main structure           */
5683b9b51feSCy Schubert /*              arg(I)   - pointer to local context to use                  */
5693b9b51feSCy Schubert /*              iph(I)   - pointer to hash table                            */
5703b9b51feSCy Schubert /*              ipe(I)   - pointer to hash table entry to remove            */
5713b9b51feSCy Schubert /*                                                                          */
5723b9b51feSCy Schubert /* Delete an entry from a hash table.                                       */
5733b9b51feSCy Schubert /* ------------------------------------------------------------------------ */
5743b9b51feSCy Schubert static int
ipf_htent_remove(ipf_main_softc_t * softc,void * arg,iphtable_t * iph,iphtent_t * ipe)575064a5a95SCy Schubert ipf_htent_remove(ipf_main_softc_t *softc, void *arg, iphtable_t *iph,
576064a5a95SCy Schubert 	iphtent_t *ipe)
5773b9b51feSCy Schubert {
5783b9b51feSCy Schubert 
5793b9b51feSCy Schubert 	if (iph->iph_tail == &ipe->ipe_next)
5803b9b51feSCy Schubert 		iph->iph_tail = ipe->ipe_pnext;
5813b9b51feSCy Schubert 
5823b9b51feSCy Schubert 	if (ipe->ipe_hnext != NULL)
5833b9b51feSCy Schubert 		ipe->ipe_hnext->ipe_phnext = ipe->ipe_phnext;
5843b9b51feSCy Schubert 	if (ipe->ipe_phnext != NULL)
5853b9b51feSCy Schubert 		*ipe->ipe_phnext = ipe->ipe_hnext;
5863b9b51feSCy Schubert 	ipe->ipe_phnext = NULL;
5873b9b51feSCy Schubert 	ipe->ipe_hnext = NULL;
5883b9b51feSCy Schubert 
5893b9b51feSCy Schubert 	if (ipe->ipe_dnext != NULL)
5903b9b51feSCy Schubert 		ipe->ipe_dnext->ipe_pdnext = ipe->ipe_pdnext;
5913b9b51feSCy Schubert 	if (ipe->ipe_pdnext != NULL)
5923b9b51feSCy Schubert 		*ipe->ipe_pdnext = ipe->ipe_dnext;
5933b9b51feSCy Schubert 	ipe->ipe_pdnext = NULL;
5943b9b51feSCy Schubert 	ipe->ipe_dnext = NULL;
5953b9b51feSCy Schubert 
5963b9b51feSCy Schubert 	if (ipe->ipe_next != NULL)
5973b9b51feSCy Schubert 		ipe->ipe_next->ipe_pnext = ipe->ipe_pnext;
5983b9b51feSCy Schubert 	if (ipe->ipe_pnext != NULL)
5993b9b51feSCy Schubert 		*ipe->ipe_pnext = ipe->ipe_next;
6003b9b51feSCy Schubert 	ipe->ipe_pnext = NULL;
6013b9b51feSCy Schubert 	ipe->ipe_next = NULL;
6023b9b51feSCy Schubert 
6033b9b51feSCy Schubert 	switch (iph->iph_type & ~IPHASH_ANON)
6043b9b51feSCy Schubert 	{
6053b9b51feSCy Schubert 	case IPHASH_GROUPMAP :
6063b9b51feSCy Schubert 		if (ipe->ipe_group != NULL)
6073b9b51feSCy Schubert 			ipf_group_del(softc, ipe->ipe_ptr, NULL);
6083b9b51feSCy Schubert 		break;
6093b9b51feSCy Schubert 
6103b9b51feSCy Schubert 	default :
6113b9b51feSCy Schubert 		ipe->ipe_ptr = NULL;
6123b9b51feSCy Schubert 		ipe->ipe_value = 0;
6133b9b51feSCy Schubert 		break;
6143b9b51feSCy Schubert 	}
6153b9b51feSCy Schubert 
6168c82b374SCy Schubert 	return (ipf_htent_deref(arg, ipe));
6173b9b51feSCy Schubert }
6183b9b51feSCy Schubert 
6193b9b51feSCy Schubert 
6203b9b51feSCy Schubert /* ------------------------------------------------------------------------ */
6213b9b51feSCy Schubert /* Function:    ipf_htable_deref                                            */
6223b9b51feSCy Schubert /* Returns:     int       - 0 = success, else error                         */
6233b9b51feSCy Schubert /* Parameters:  softc(I)  - pointer to soft context main structure          */
6243b9b51feSCy Schubert /*              arg(I)    - pointer to local context to use                 */
6253b9b51feSCy Schubert /*              object(I) - pointer to hash table                           */
6263b9b51feSCy Schubert /*                                                                          */
6273b9b51feSCy Schubert /* ------------------------------------------------------------------------ */
6283b9b51feSCy Schubert static int
ipf_htable_deref(ipf_main_softc_t * softc,void * arg,void * object)629064a5a95SCy Schubert ipf_htable_deref(ipf_main_softc_t *softc, void *arg, void *object)
6303b9b51feSCy Schubert {
6313b9b51feSCy Schubert 	ipf_htable_softc_t *softh = arg;
6323b9b51feSCy Schubert 	iphtable_t *iph = object;
6333b9b51feSCy Schubert 	int refs;
6343b9b51feSCy Schubert 
6353b9b51feSCy Schubert 	iph->iph_ref--;
6363b9b51feSCy Schubert 	refs = iph->iph_ref;
6373b9b51feSCy Schubert 
6383b9b51feSCy Schubert 	if (iph->iph_ref == 0) {
6393b9b51feSCy Schubert 		ipf_htable_free(softh, iph);
6403b9b51feSCy Schubert 	}
6413b9b51feSCy Schubert 
6428c82b374SCy Schubert 	return (refs);
6433b9b51feSCy Schubert }
6443b9b51feSCy Schubert 
6453b9b51feSCy Schubert 
6463b9b51feSCy Schubert /* ------------------------------------------------------------------------ */
6473b9b51feSCy Schubert /* Function:    ipf_htent_deref                                             */
6483b9b51feSCy Schubert /* Parameters:  arg(I) - pointer to local context to use                    */
6493b9b51feSCy Schubert /*              ipe(I) -                                                    */
6503b9b51feSCy Schubert /*                                                                          */
6513b9b51feSCy Schubert /* ------------------------------------------------------------------------ */
6523b9b51feSCy Schubert static int
ipf_htent_deref(void * arg,iphtent_t * ipe)653064a5a95SCy Schubert ipf_htent_deref(void *arg, iphtent_t *ipe)
6543b9b51feSCy Schubert {
6553b9b51feSCy Schubert 	ipf_htable_softc_t *softh = arg;
6563b9b51feSCy Schubert 
6573b9b51feSCy Schubert 	ipe->ipe_ref--;
6583b9b51feSCy Schubert 	if (ipe->ipe_ref == 0) {
6593b9b51feSCy Schubert 		softh->ipf_nhtnodes[ipe->ipe_unit + 1]--;
6603b9b51feSCy Schubert 		KFREE(ipe);
6613b9b51feSCy Schubert 
6628c82b374SCy Schubert 		return (0);
6633b9b51feSCy Schubert 	}
6643b9b51feSCy Schubert 
6658c82b374SCy Schubert 	return (ipe->ipe_ref);
6663b9b51feSCy Schubert }
6673b9b51feSCy Schubert 
6683b9b51feSCy Schubert 
6693b9b51feSCy Schubert /* ------------------------------------------------------------------------ */
6703b9b51feSCy Schubert /* Function:    ipf_htable_exists                                           */
6713b9b51feSCy Schubert /* Parameters:  arg(I) - pointer to local context to use                    */
6723b9b51feSCy Schubert /*                                                                          */
6733b9b51feSCy Schubert /* ------------------------------------------------------------------------ */
6743b9b51feSCy Schubert static void *
ipf_htable_exists(void * arg,int unit,char * name)675064a5a95SCy Schubert ipf_htable_exists(void *arg, int unit, char *name)
6763b9b51feSCy Schubert {
6773b9b51feSCy Schubert 	ipf_htable_softc_t *softh = arg;
6783b9b51feSCy Schubert 	iphtable_t *iph;
6793b9b51feSCy Schubert 
6803b9b51feSCy Schubert 	if (unit == IPL_LOGALL) {
6813b9b51feSCy Schubert 		int i;
6823b9b51feSCy Schubert 
6833b9b51feSCy Schubert 		for (i = 0; i <= LOOKUP_POOL_MAX; i++) {
6843b9b51feSCy Schubert 			for (iph = softh->ipf_htables[i]; iph != NULL;
6853b9b51feSCy Schubert 			     iph = iph->iph_next) {
6863b9b51feSCy Schubert 				if (strncmp(iph->iph_name, name,
6873b9b51feSCy Schubert 					    sizeof(iph->iph_name)) == 0)
6883b9b51feSCy Schubert 					break;
6893b9b51feSCy Schubert 			}
6903b9b51feSCy Schubert 			if (iph != NULL)
6913b9b51feSCy Schubert 				break;
6923b9b51feSCy Schubert 		}
6933b9b51feSCy Schubert 	} else {
6943b9b51feSCy Schubert 		for (iph = softh->ipf_htables[unit + 1]; iph != NULL;
6953b9b51feSCy Schubert 		     iph = iph->iph_next) {
6963b9b51feSCy Schubert 			if (strncmp(iph->iph_name, name,
6973b9b51feSCy Schubert 				    sizeof(iph->iph_name)) == 0)
6983b9b51feSCy Schubert 				break;
6993b9b51feSCy Schubert 		}
7003b9b51feSCy Schubert 	}
7018c82b374SCy Schubert 	return (iph);
7023b9b51feSCy Schubert }
7033b9b51feSCy Schubert 
7043b9b51feSCy Schubert 
7053b9b51feSCy Schubert /* ------------------------------------------------------------------------ */
7063b9b51feSCy Schubert /* Function:    ipf_htable_select_add_ref                                   */
7073b9b51feSCy Schubert /* Returns:     void *  - NULL = failure, else pointer to the hash table    */
7083b9b51feSCy Schubert /* Parameters:  arg(I)  - pointer to local context to use                   */
7093b9b51feSCy Schubert /*              unit(I) - ipfilter device to which we are working on        */
7103b9b51feSCy Schubert /*              name(I) - name of the hash table                            */
7113b9b51feSCy Schubert /*                                                                          */
7123b9b51feSCy Schubert /* ------------------------------------------------------------------------ */
7133b9b51feSCy Schubert static void *
ipf_htable_select_add_ref(void * arg,int unit,char * name)714064a5a95SCy Schubert ipf_htable_select_add_ref(void *arg, int unit, char *name)
7153b9b51feSCy Schubert {
7163b9b51feSCy Schubert 	iphtable_t *iph;
7173b9b51feSCy Schubert 
7183b9b51feSCy Schubert 	iph = ipf_htable_exists(arg, unit, name);
7193b9b51feSCy Schubert 	if (iph != NULL) {
7203b9b51feSCy Schubert 		ATOMIC_INC32(iph->iph_ref);
7213b9b51feSCy Schubert 	}
7228c82b374SCy Schubert 	return (iph);
7233b9b51feSCy Schubert }
7243b9b51feSCy Schubert 
7253b9b51feSCy Schubert 
7263b9b51feSCy Schubert /* ------------------------------------------------------------------------ */
7273b9b51feSCy Schubert /* Function:    ipf_htable_find                                             */
7283b9b51feSCy Schubert /* Returns:     void *  - NULL = failure, else pointer to the hash table    */
7293b9b51feSCy Schubert /* Parameters:  arg(I)  - pointer to local context to use                   */
7303b9b51feSCy Schubert /*              unit(I) - ipfilter device to which we are working on        */
7313b9b51feSCy Schubert /*              name(I) - name of the hash table                            */
7323b9b51feSCy Schubert /*                                                                          */
7333b9b51feSCy Schubert /* This function is exposed becaues it is used in the group-map feature.    */
7343b9b51feSCy Schubert /* ------------------------------------------------------------------------ */
7353b9b51feSCy Schubert iphtable_t *
ipf_htable_find(void * arg,int unit,char * name)736064a5a95SCy Schubert ipf_htable_find(void *arg, int unit, char *name)
7373b9b51feSCy Schubert {
7383b9b51feSCy Schubert 	iphtable_t *iph;
7393b9b51feSCy Schubert 
7403b9b51feSCy Schubert 	iph = ipf_htable_exists(arg, unit, name);
7413b9b51feSCy Schubert 	if ((iph != NULL) && (iph->iph_flags & IPHASH_DELETE) == 0)
7428c82b374SCy Schubert 		return (iph);
7433b9b51feSCy Schubert 
7448c82b374SCy Schubert 	return (NULL);
7453b9b51feSCy Schubert }
7463b9b51feSCy Schubert 
7473b9b51feSCy Schubert 
7483b9b51feSCy Schubert /* ------------------------------------------------------------------------ */
7493b9b51feSCy Schubert /* Function:    ipf_htable_flush                                            */
7503b9b51feSCy Schubert /* Returns:     size_t   - number of entries flushed                        */
7513b9b51feSCy Schubert /* Parameters:  softc(I) - pointer to soft context main structure           */
7523b9b51feSCy Schubert /*              arg(I)   - pointer to local context to use                  */
7533b9b51feSCy Schubert /*              op(I)    - pointer to lookup operation data                 */
7543b9b51feSCy Schubert /*                                                                          */
7553b9b51feSCy Schubert /* ------------------------------------------------------------------------ */
7563b9b51feSCy Schubert static size_t
ipf_htable_flush(ipf_main_softc_t * softc,void * arg,iplookupflush_t * op)757064a5a95SCy Schubert ipf_htable_flush(ipf_main_softc_t *softc, void *arg, iplookupflush_t *op)
7583b9b51feSCy Schubert {
7593b9b51feSCy Schubert 	ipf_htable_softc_t *softh = arg;
7603b9b51feSCy Schubert 	iphtable_t *iph;
7613b9b51feSCy Schubert 	size_t freed;
7623b9b51feSCy Schubert 	int i;
7633b9b51feSCy Schubert 
7643b9b51feSCy Schubert 	freed = 0;
7653b9b51feSCy Schubert 
7663b9b51feSCy Schubert 	for (i = -1; i <= IPL_LOGMAX; i++) {
7673b9b51feSCy Schubert 		if (op->iplf_unit == i || op->iplf_unit == IPL_LOGALL) {
7683b9b51feSCy Schubert 			while ((iph = softh->ipf_htables[i + 1]) != NULL) {
7693b9b51feSCy Schubert 				if (ipf_htable_remove(softc, arg, iph) == 0) {
7703b9b51feSCy Schubert 					freed++;
7713b9b51feSCy Schubert 				} else {
7723b9b51feSCy Schubert 					iph->iph_flags |= IPHASH_DELETE;
7733b9b51feSCy Schubert 				}
7743b9b51feSCy Schubert 			}
7753b9b51feSCy Schubert 		}
7763b9b51feSCy Schubert 	}
7773b9b51feSCy Schubert 
7788c82b374SCy Schubert 	return (freed);
7793b9b51feSCy Schubert }
7803b9b51feSCy Schubert 
7813b9b51feSCy Schubert 
7823b9b51feSCy Schubert /* ------------------------------------------------------------------------ */
7833b9b51feSCy Schubert /* Function:    ipf_htable_node_add                                         */
7843b9b51feSCy Schubert /* Returns:     int      - 0 = success, else error                          */
7853b9b51feSCy Schubert /* Parameters:  softc(I) - pointer to soft context main structure           */
7863b9b51feSCy Schubert /*              arg(I)   - pointer to local context to use                  */
7873b9b51feSCy Schubert /*              op(I)    - pointer to lookup operation data                 */
7883b9b51feSCy Schubert /*              uid(I)   - real uid of process doing operation              */
7893b9b51feSCy Schubert /*                                                                          */
7903b9b51feSCy Schubert /* ------------------------------------------------------------------------ */
7913b9b51feSCy Schubert static int
ipf_htable_node_add(ipf_main_softc_t * softc,void * arg,iplookupop_t * op,int uid)792064a5a95SCy Schubert ipf_htable_node_add(ipf_main_softc_t *softc, void *arg, iplookupop_t *op,
793064a5a95SCy Schubert 	int uid)
7943b9b51feSCy Schubert {
7953b9b51feSCy Schubert 	iphtable_t *iph;
7963b9b51feSCy Schubert 	iphtent_t hte;
7973b9b51feSCy Schubert 	int err;
7983b9b51feSCy Schubert 
7993b9b51feSCy Schubert 	if (op->iplo_size != sizeof(hte)) {
8003b9b51feSCy Schubert 		IPFERROR(30018);
8018c82b374SCy Schubert 		return (EINVAL);
8023b9b51feSCy Schubert 	}
8033b9b51feSCy Schubert 
8043b9b51feSCy Schubert 	err = COPYIN(op->iplo_struct, &hte, sizeof(hte));
8053b9b51feSCy Schubert 	if (err != 0) {
8063b9b51feSCy Schubert 		IPFERROR(30019);
8078c82b374SCy Schubert 		return (EFAULT);
8083b9b51feSCy Schubert 	}
8093b9b51feSCy Schubert 	hte.ipe_uid = uid;
8103b9b51feSCy Schubert 
8113b9b51feSCy Schubert 	iph = ipf_htable_find(arg, op->iplo_unit, op->iplo_name);
8123b9b51feSCy Schubert 	if (iph == NULL) {
8133b9b51feSCy Schubert 		IPFERROR(30020);
8148c82b374SCy Schubert 		return (ESRCH);
8153b9b51feSCy Schubert 	}
8163b9b51feSCy Schubert 
8173b9b51feSCy Schubert 	if (ipf_htent_find(iph, &hte) != NULL) {
8183b9b51feSCy Schubert 		IPFERROR(30021);
8198c82b374SCy Schubert 		return (EEXIST);
8203b9b51feSCy Schubert 	}
8213b9b51feSCy Schubert 
8223b9b51feSCy Schubert 	err = ipf_htent_insert(softc, arg, iph, &hte);
8233b9b51feSCy Schubert 
8248c82b374SCy Schubert 	return (err);
8253b9b51feSCy Schubert }
8263b9b51feSCy Schubert 
8273b9b51feSCy Schubert 
8283b9b51feSCy Schubert /* ------------------------------------------------------------------------ */
8293b9b51feSCy Schubert /* Function:    ipf_htent_insert                                            */
8303b9b51feSCy Schubert /* Returns:     int      - 0 = success, -1 =  error                         */
8313b9b51feSCy Schubert /* Parameters:  softc(I) - pointer to soft context main structure           */
8323b9b51feSCy Schubert /*              arg(I)   - pointer to local context to use                  */
8333b9b51feSCy Schubert /*              op(I)    - pointer to lookup operation data                 */
8343b9b51feSCy Schubert /*              ipeo(I)  -                                                  */
8353b9b51feSCy Schubert /*                                                                          */
8363b9b51feSCy Schubert /* Add an entry to a hash table.                                            */
8373b9b51feSCy Schubert /* ------------------------------------------------------------------------ */
8383b9b51feSCy Schubert static int
ipf_htent_insert(ipf_main_softc_t * softc,void * arg,iphtable_t * iph,iphtent_t * ipeo)839064a5a95SCy Schubert ipf_htent_insert(ipf_main_softc_t *softc, void *arg, iphtable_t *iph,
840064a5a95SCy Schubert 	iphtent_t *ipeo)
8413b9b51feSCy Schubert {
8423b9b51feSCy Schubert 	ipf_htable_softc_t *softh = arg;
8433b9b51feSCy Schubert 	iphtent_t *ipe;
8443b9b51feSCy Schubert 	u_int hv;
8453b9b51feSCy Schubert 	int bits;
8463b9b51feSCy Schubert 
8473b9b51feSCy Schubert 	KMALLOC(ipe, iphtent_t *);
8483b9b51feSCy Schubert 	if (ipe == NULL)
8498c82b374SCy Schubert 		return (-1);
8503b9b51feSCy Schubert 
8513b9b51feSCy Schubert 	bcopy((char *)ipeo, (char *)ipe, sizeof(*ipe));
8523b9b51feSCy Schubert 	ipe->ipe_addr.i6[0] &= ipe->ipe_mask.i6[0];
8533b9b51feSCy Schubert 	if (ipe->ipe_family == AF_INET) {
8543b9b51feSCy Schubert 		bits = count4bits(ipe->ipe_mask.in4_addr);
8553b9b51feSCy Schubert 		ipe->ipe_addr.i6[1] = 0;
8563b9b51feSCy Schubert 		ipe->ipe_addr.i6[2] = 0;
8573b9b51feSCy Schubert 		ipe->ipe_addr.i6[3] = 0;
8583b9b51feSCy Schubert 		ipe->ipe_mask.i6[1] = 0;
8593b9b51feSCy Schubert 		ipe->ipe_mask.i6[2] = 0;
8603b9b51feSCy Schubert 		ipe->ipe_mask.i6[3] = 0;
8613b9b51feSCy Schubert 		hv = IPE_V4_HASH_FN(ipe->ipe_addr.in4_addr,
8623b9b51feSCy Schubert 				    ipe->ipe_mask.in4_addr, iph->iph_size);
8633b9b51feSCy Schubert 	} else
8643b9b51feSCy Schubert #ifdef USE_INET6
8653b9b51feSCy Schubert 	if (ipe->ipe_family == AF_INET6) {
8663b9b51feSCy Schubert 		ipe->ipe_addr.i6[1] &= ipe->ipe_mask.i6[1];
8673b9b51feSCy Schubert 		ipe->ipe_addr.i6[2] &= ipe->ipe_mask.i6[2];
8683b9b51feSCy Schubert 		ipe->ipe_addr.i6[3] &= ipe->ipe_mask.i6[3];
8693b9b51feSCy Schubert 
8703b9b51feSCy Schubert 		bits = count6bits(ipe->ipe_mask.i6);
8713b9b51feSCy Schubert 		hv = IPE_V6_HASH_FN(ipe->ipe_addr.i6,
8723b9b51feSCy Schubert 				    ipe->ipe_mask.i6, iph->iph_size);
8733b9b51feSCy Schubert 	} else
8743b9b51feSCy Schubert #endif
8753b9b51feSCy Schubert 	{
8763b9b51feSCy Schubert 		KFREE(ipe);
8778c82b374SCy Schubert 		return (-1);
8783b9b51feSCy Schubert 	}
8793b9b51feSCy Schubert 
8803b9b51feSCy Schubert 	ipe->ipe_owner = iph;
8813b9b51feSCy Schubert 	ipe->ipe_ref = 1;
8823b9b51feSCy Schubert 	ipe->ipe_hnext = iph->iph_table[hv];
8833b9b51feSCy Schubert 	ipe->ipe_phnext = iph->iph_table + hv;
8843b9b51feSCy Schubert 
8853b9b51feSCy Schubert 	if (iph->iph_table[hv] != NULL)
8863b9b51feSCy Schubert 		iph->iph_table[hv]->ipe_phnext = &ipe->ipe_hnext;
8873b9b51feSCy Schubert 	iph->iph_table[hv] = ipe;
8883b9b51feSCy Schubert 
8893b9b51feSCy Schubert 	ipe->ipe_pnext = iph->iph_tail;
8903b9b51feSCy Schubert 	*iph->iph_tail = ipe;
8913b9b51feSCy Schubert 	iph->iph_tail = &ipe->ipe_next;
8923b9b51feSCy Schubert 	ipe->ipe_next = NULL;
8933b9b51feSCy Schubert 
8943b9b51feSCy Schubert 	if (ipe->ipe_die != 0) {
8953b9b51feSCy Schubert 		/*
8963b9b51feSCy Schubert 		 * If the new node has a given expiration time, insert it
8973b9b51feSCy Schubert 		 * into the list of expiring nodes with the ones to be
8983b9b51feSCy Schubert 		 * removed first added to the front of the list. The
8993b9b51feSCy Schubert 		 * insertion is O(n) but it is kept sorted for quick scans
9003b9b51feSCy Schubert 		 * at expiration interval checks.
9013b9b51feSCy Schubert 		 */
9023b9b51feSCy Schubert 		iphtent_t *n;
9033b9b51feSCy Schubert 
9043b9b51feSCy Schubert 		ipe->ipe_die = softc->ipf_ticks + IPF_TTLVAL(ipe->ipe_die);
9053b9b51feSCy Schubert 		for (n = softh->ipf_node_explist; n != NULL; n = n->ipe_dnext) {
9063b9b51feSCy Schubert 			if (ipe->ipe_die < n->ipe_die)
9073b9b51feSCy Schubert 				break;
9083b9b51feSCy Schubert 			if (n->ipe_dnext == NULL) {
9093b9b51feSCy Schubert 				/*
9103b9b51feSCy Schubert 				 * We've got to the last node and everything
9113b9b51feSCy Schubert 				 * wanted to be expired before this new node,
9123b9b51feSCy Schubert 				 * so we have to tack it on the end...
9133b9b51feSCy Schubert 				 */
9143b9b51feSCy Schubert 				n->ipe_dnext = ipe;
9153b9b51feSCy Schubert 				ipe->ipe_pdnext = &n->ipe_dnext;
9163b9b51feSCy Schubert 				n = NULL;
9173b9b51feSCy Schubert 				break;
9183b9b51feSCy Schubert 			}
9193b9b51feSCy Schubert 		}
9203b9b51feSCy Schubert 
9213b9b51feSCy Schubert 		if (softh->ipf_node_explist == NULL) {
9223b9b51feSCy Schubert 			softh->ipf_node_explist = ipe;
9233b9b51feSCy Schubert 			ipe->ipe_pdnext = &softh->ipf_node_explist;
9243b9b51feSCy Schubert 		} else if (n != NULL) {
9253b9b51feSCy Schubert 			ipe->ipe_dnext = n;
9263b9b51feSCy Schubert 			ipe->ipe_pdnext = n->ipe_pdnext;
9273b9b51feSCy Schubert 			n->ipe_pdnext = &ipe->ipe_dnext;
9283b9b51feSCy Schubert 		}
9293b9b51feSCy Schubert 	}
9303b9b51feSCy Schubert 
9313b9b51feSCy Schubert 	if (ipe->ipe_family == AF_INET) {
9323b9b51feSCy Schubert 		ipf_inet_mask_add(bits, &iph->iph_v4_masks);
9333b9b51feSCy Schubert 	}
9343b9b51feSCy Schubert #ifdef USE_INET6
9353b9b51feSCy Schubert 	else if (ipe->ipe_family == AF_INET6) {
9363b9b51feSCy Schubert 		ipf_inet6_mask_add(bits, &ipe->ipe_mask, &iph->iph_v6_masks);
9373b9b51feSCy Schubert 	}
9383b9b51feSCy Schubert #endif
9393b9b51feSCy Schubert 
9403b9b51feSCy Schubert 	switch (iph->iph_type & ~IPHASH_ANON)
9413b9b51feSCy Schubert 	{
9423b9b51feSCy Schubert 	case IPHASH_GROUPMAP :
9433b9b51feSCy Schubert 		ipe->ipe_ptr = ipf_group_add(softc, ipe->ipe_group, NULL,
9443b9b51feSCy Schubert 					   iph->iph_flags, IPL_LOGIPF,
9453b9b51feSCy Schubert 					   softc->ipf_active);
9463b9b51feSCy Schubert 		break;
9473b9b51feSCy Schubert 
9483b9b51feSCy Schubert 	default :
9493b9b51feSCy Schubert 		ipe->ipe_ptr = NULL;
9503b9b51feSCy Schubert 		ipe->ipe_value = 0;
9513b9b51feSCy Schubert 		break;
9523b9b51feSCy Schubert 	}
9533b9b51feSCy Schubert 
9543b9b51feSCy Schubert 	ipe->ipe_unit = iph->iph_unit;
9553b9b51feSCy Schubert 	softh->ipf_nhtnodes[ipe->ipe_unit + 1]++;
9563b9b51feSCy Schubert 
9578c82b374SCy Schubert 	return (0);
9583b9b51feSCy Schubert }
9593b9b51feSCy Schubert 
9603b9b51feSCy Schubert 
9613b9b51feSCy Schubert /* ------------------------------------------------------------------------ */
9623b9b51feSCy Schubert /* Function:    ipf_htent_find                                              */
9633b9b51feSCy Schubert /* Returns:     int     - 0 = success, else error                           */
9643b9b51feSCy Schubert /* Parameters:  iph(I)  - pointer to table to search                        */
9653b9b51feSCy Schubert /*              ipeo(I) - pointer to entry to find                          */
9663b9b51feSCy Schubert /*                                                                          */
9673b9b51feSCy Schubert /* While it isn't absolutely necessary to for the address and mask to be    */
9683b9b51feSCy Schubert /* passed in through an iphtent_t structure, one is always present when it  */
9693b9b51feSCy Schubert /* is time to call this function, so it is just more convenient.            */
9703b9b51feSCy Schubert /* ------------------------------------------------------------------------ */
9713b9b51feSCy Schubert static iphtent_t *
ipf_htent_find(iphtable_t * iph,iphtent_t * ipeo)972064a5a95SCy Schubert ipf_htent_find(iphtable_t *iph, iphtent_t *ipeo)
9733b9b51feSCy Schubert {
9743b9b51feSCy Schubert 	iphtent_t ipe, *ent;
9753b9b51feSCy Schubert 	u_int hv;
9763b9b51feSCy Schubert 	int bits;
9773b9b51feSCy Schubert 
9783b9b51feSCy Schubert 	bcopy((char *)ipeo, (char *)&ipe, sizeof(ipe));
9793b9b51feSCy Schubert 	ipe.ipe_addr.i6[0] &= ipe.ipe_mask.i6[0];
9803b9b51feSCy Schubert 	ipe.ipe_addr.i6[1] &= ipe.ipe_mask.i6[1];
9813b9b51feSCy Schubert 	ipe.ipe_addr.i6[2] &= ipe.ipe_mask.i6[2];
9823b9b51feSCy Schubert 	ipe.ipe_addr.i6[3] &= ipe.ipe_mask.i6[3];
9833b9b51feSCy Schubert 	if (ipe.ipe_family == AF_INET) {
9843b9b51feSCy Schubert 		bits = count4bits(ipe.ipe_mask.in4_addr);
9853b9b51feSCy Schubert 		ipe.ipe_addr.i6[1] = 0;
9863b9b51feSCy Schubert 		ipe.ipe_addr.i6[2] = 0;
9873b9b51feSCy Schubert 		ipe.ipe_addr.i6[3] = 0;
9883b9b51feSCy Schubert 		ipe.ipe_mask.i6[1] = 0;
9893b9b51feSCy Schubert 		ipe.ipe_mask.i6[2] = 0;
9903b9b51feSCy Schubert 		ipe.ipe_mask.i6[3] = 0;
9913b9b51feSCy Schubert 		hv = IPE_V4_HASH_FN(ipe.ipe_addr.in4_addr,
9923b9b51feSCy Schubert 				    ipe.ipe_mask.in4_addr, iph->iph_size);
9933b9b51feSCy Schubert 	} else
9943b9b51feSCy Schubert #ifdef USE_INET6
9953b9b51feSCy Schubert 	if (ipe.ipe_family == AF_INET6) {
9963b9b51feSCy Schubert 		bits = count6bits(ipe.ipe_mask.i6);
9973b9b51feSCy Schubert 		hv = IPE_V6_HASH_FN(ipe.ipe_addr.i6,
9983b9b51feSCy Schubert 				    ipe.ipe_mask.i6, iph->iph_size);
9993b9b51feSCy Schubert 	} else
10003b9b51feSCy Schubert #endif
10018c82b374SCy Schubert 		return (NULL);
10023b9b51feSCy Schubert 
10033b9b51feSCy Schubert 	for (ent = iph->iph_table[hv]; ent != NULL; ent = ent->ipe_hnext) {
10043b9b51feSCy Schubert 		if (ent->ipe_family != ipe.ipe_family)
10053b9b51feSCy Schubert 			continue;
10063b9b51feSCy Schubert 		if (IP6_NEQ(&ipe.ipe_addr, &ent->ipe_addr))
10073b9b51feSCy Schubert 			continue;
10083b9b51feSCy Schubert 		if (IP6_NEQ(&ipe.ipe_mask, &ent->ipe_mask))
10093b9b51feSCy Schubert 			continue;
10103b9b51feSCy Schubert 		break;
10113b9b51feSCy Schubert 	}
10123b9b51feSCy Schubert 
10138c82b374SCy Schubert 	return (ent);
10143b9b51feSCy Schubert }
10153b9b51feSCy Schubert 
10163b9b51feSCy Schubert 
10173b9b51feSCy Schubert /* ------------------------------------------------------------------------ */
10183b9b51feSCy Schubert /* Function:    ipf_iphmfindgroup                                           */
10193b9b51feSCy Schubert /* Returns:     int      - 0 = success, else error                          */
10203b9b51feSCy Schubert /* Parameters:  softc(I) - pointer to soft context main structure           */
10213b9b51feSCy Schubert /*              tptr(I)  -                                                  */
10223b9b51feSCy Schubert /*              aptr(I)  -                                                  */
10233b9b51feSCy Schubert /*                                                                          */
10243b9b51feSCy Schubert /* Search a hash table for a matching entry and return the pointer stored   */
10253b9b51feSCy Schubert /* in it for use as the next group of rules to search.                      */
10263b9b51feSCy Schubert /*                                                                          */
10273b9b51feSCy Schubert /* This function is exposed becaues it is used in the group-map feature.    */
10283b9b51feSCy Schubert /* ------------------------------------------------------------------------ */
10293b9b51feSCy Schubert void *
ipf_iphmfindgroup(ipf_main_softc_t * softc,void * tptr,void * aptr)1030064a5a95SCy Schubert ipf_iphmfindgroup(ipf_main_softc_t *softc, void *tptr, void *aptr)
10313b9b51feSCy Schubert {
10323b9b51feSCy Schubert 	struct in_addr *addr;
10333b9b51feSCy Schubert 	iphtable_t *iph;
10343b9b51feSCy Schubert 	iphtent_t *ipe;
10353b9b51feSCy Schubert 	void *rval;
10363b9b51feSCy Schubert 
10373b9b51feSCy Schubert 	READ_ENTER(&softc->ipf_poolrw);
10383b9b51feSCy Schubert 	iph = tptr;
10393b9b51feSCy Schubert 	addr = aptr;
10403b9b51feSCy Schubert 
10413b9b51feSCy Schubert 	ipe = ipf_iphmfind(iph, addr);
10423b9b51feSCy Schubert 	if (ipe != NULL)
10433b9b51feSCy Schubert 		rval = ipe->ipe_ptr;
10443b9b51feSCy Schubert 	else
10453b9b51feSCy Schubert 		rval = NULL;
10463b9b51feSCy Schubert 	RWLOCK_EXIT(&softc->ipf_poolrw);
10478c82b374SCy Schubert 	return (rval);
10483b9b51feSCy Schubert }
10493b9b51feSCy Schubert 
10503b9b51feSCy Schubert 
10513b9b51feSCy Schubert /* ------------------------------------------------------------------------ */
10523b9b51feSCy Schubert /* Function:    ipf_iphmfindip                                              */
10533b9b51feSCy Schubert /* Returns:     int     - 0 == +ve match, -1 == error, 1 == -ve/no match    */
10543b9b51feSCy Schubert /* Parameters:  softc(I)     - pointer to soft context main structure       */
10553b9b51feSCy Schubert /*              tptr(I)      - pointer to the pool to search                */
10563b9b51feSCy Schubert /*              ipversion(I) - IP protocol version (4 or 6)                 */
10573b9b51feSCy Schubert /*              aptr(I)      - pointer to address information               */
10583b9b51feSCy Schubert /*              bytes(I)     - packet length                                */
10593b9b51feSCy Schubert /*                                                                          */
10603b9b51feSCy Schubert /* Search the hash table for a given address and return a search result.    */
10613b9b51feSCy Schubert /* ------------------------------------------------------------------------ */
10623b9b51feSCy Schubert static int
ipf_iphmfindip(ipf_main_softc_t * softc,void * tptr,int ipversion,void * aptr,u_int bytes)1063064a5a95SCy Schubert ipf_iphmfindip(ipf_main_softc_t *softc, void *tptr, int ipversion, void *aptr,
1064064a5a95SCy Schubert 	u_int bytes)
10653b9b51feSCy Schubert {
10663b9b51feSCy Schubert 	struct in_addr *addr;
10673b9b51feSCy Schubert 	iphtable_t *iph;
10683b9b51feSCy Schubert 	iphtent_t *ipe;
10693b9b51feSCy Schubert 	int rval;
10703b9b51feSCy Schubert 
10713b9b51feSCy Schubert 	if (tptr == NULL || aptr == NULL)
10728c82b374SCy Schubert 		return (-1);
10733b9b51feSCy Schubert 
10743b9b51feSCy Schubert 	iph = tptr;
10753b9b51feSCy Schubert 	addr = aptr;
10763b9b51feSCy Schubert 
10773b9b51feSCy Schubert 	READ_ENTER(&softc->ipf_poolrw);
10783b9b51feSCy Schubert 	if (ipversion == 4) {
10793b9b51feSCy Schubert 		ipe = ipf_iphmfind(iph, addr);
10803b9b51feSCy Schubert #ifdef USE_INET6
10813b9b51feSCy Schubert 	} else if (ipversion == 6) {
10823b9b51feSCy Schubert 		ipe = ipf_iphmfind6(iph, (i6addr_t *)addr);
10833b9b51feSCy Schubert #endif
10843b9b51feSCy Schubert 	} else {
10853b9b51feSCy Schubert 		ipe = NULL;
10863b9b51feSCy Schubert 	}
10873b9b51feSCy Schubert 
10883b9b51feSCy Schubert 	if (ipe != NULL) {
10893b9b51feSCy Schubert 		rval = 0;
10903b9b51feSCy Schubert 		ipe->ipe_hits++;
10913b9b51feSCy Schubert 		ipe->ipe_bytes += bytes;
10923b9b51feSCy Schubert 	} else {
10933b9b51feSCy Schubert 		rval = 1;
10943b9b51feSCy Schubert 	}
10953b9b51feSCy Schubert 	RWLOCK_EXIT(&softc->ipf_poolrw);
10968c82b374SCy Schubert 	return (rval);
10973b9b51feSCy Schubert }
10983b9b51feSCy Schubert 
10993b9b51feSCy Schubert 
11003b9b51feSCy Schubert /* ------------------------------------------------------------------------ */
11013b9b51feSCy Schubert /* Function:    ipf_iphmfindip                                              */
11023b9b51feSCy Schubert /* Parameters:  iph(I)  - pointer to hash table                             */
11033b9b51feSCy Schubert /*              addr(I) - pointer to IPv4 address                           */
11043b9b51feSCy Schubert /* Locks:  ipf_poolrw                                                       */
11053b9b51feSCy Schubert /*                                                                          */
11063b9b51feSCy Schubert /* ------------------------------------------------------------------------ */
11073b9b51feSCy Schubert static iphtent_t *
ipf_iphmfind(iphtable_t * iph,struct in_addr * addr)1108064a5a95SCy Schubert ipf_iphmfind(iphtable_t *iph, struct in_addr *addr)
11093b9b51feSCy Schubert {
11103b9b51feSCy Schubert 	u_32_t msk, ips;
11113b9b51feSCy Schubert 	iphtent_t *ipe;
11123b9b51feSCy Schubert 	u_int hv;
11133b9b51feSCy Schubert 	int i;
11143b9b51feSCy Schubert 
11153b9b51feSCy Schubert 	i = 0;
11163b9b51feSCy Schubert maskloop:
11173b9b51feSCy Schubert 	msk = iph->iph_v4_masks.imt4_active[i];
11183b9b51feSCy Schubert 	ips = addr->s_addr & msk;
11193b9b51feSCy Schubert 	hv = IPE_V4_HASH_FN(ips, msk, iph->iph_size);
11203b9b51feSCy Schubert 	for (ipe = iph->iph_table[hv]; (ipe != NULL); ipe = ipe->ipe_hnext) {
11213b9b51feSCy Schubert 		if ((ipe->ipe_family != AF_INET) ||
11223b9b51feSCy Schubert 		    (ipe->ipe_mask.in4_addr != msk) ||
11233b9b51feSCy Schubert 		    (ipe->ipe_addr.in4_addr != ips)) {
11243b9b51feSCy Schubert 			continue;
11253b9b51feSCy Schubert 		}
11263b9b51feSCy Schubert 		break;
11273b9b51feSCy Schubert 	}
11283b9b51feSCy Schubert 
11293b9b51feSCy Schubert 	if (ipe == NULL) {
11303b9b51feSCy Schubert 		i++;
11313b9b51feSCy Schubert 		if (i < iph->iph_v4_masks.imt4_max)
11323b9b51feSCy Schubert 			goto maskloop;
11333b9b51feSCy Schubert 	}
11348c82b374SCy Schubert 	return (ipe);
11353b9b51feSCy Schubert }
11363b9b51feSCy Schubert 
11373b9b51feSCy Schubert 
11383b9b51feSCy Schubert /* ------------------------------------------------------------------------ */
11393b9b51feSCy Schubert /* Function:    ipf_htable_iter_next                                        */
11403b9b51feSCy Schubert /* Returns:     int      - 0 = success, else error                          */
11413b9b51feSCy Schubert /* Parameters:  softc(I) - pointer to soft context main structure           */
11423b9b51feSCy Schubert /*              arg(I)   - pointer to local context to use                  */
11433b9b51feSCy Schubert /*              token(I) -                                                  */
11443b9b51feSCy Schubert /*              ilp(I)   -                                                  */
11453b9b51feSCy Schubert /*                                                                          */
11463b9b51feSCy Schubert /* ------------------------------------------------------------------------ */
11473b9b51feSCy Schubert static int
ipf_htable_iter_next(ipf_main_softc_t * softc,void * arg,ipftoken_t * token,ipflookupiter_t * ilp)1148064a5a95SCy Schubert ipf_htable_iter_next(ipf_main_softc_t *softc, void *arg, ipftoken_t *token,
1149064a5a95SCy Schubert 	ipflookupiter_t *ilp)
11503b9b51feSCy Schubert {
11513b9b51feSCy Schubert 	ipf_htable_softc_t *softh = arg;
11523b9b51feSCy Schubert 	iphtent_t *node, zn, *nextnode;
11533b9b51feSCy Schubert 	iphtable_t *iph, zp, *nextiph;
11543b9b51feSCy Schubert 	void *hnext;
11553b9b51feSCy Schubert 	int err;
11563b9b51feSCy Schubert 
11573b9b51feSCy Schubert 	err = 0;
11583b9b51feSCy Schubert 	iph = NULL;
11593b9b51feSCy Schubert 	node = NULL;
11603b9b51feSCy Schubert 	nextiph = NULL;
11613b9b51feSCy Schubert 	nextnode = NULL;
11623b9b51feSCy Schubert 
11633b9b51feSCy Schubert 	READ_ENTER(&softc->ipf_poolrw);
11643b9b51feSCy Schubert 
11653b9b51feSCy Schubert 	switch (ilp->ili_otype)
11663b9b51feSCy Schubert 	{
11673b9b51feSCy Schubert 	case IPFLOOKUPITER_LIST :
11683b9b51feSCy Schubert 		iph = token->ipt_data;
11693b9b51feSCy Schubert 		if (iph == NULL) {
11703b9b51feSCy Schubert 			nextiph = softh->ipf_htables[(int)ilp->ili_unit + 1];
11713b9b51feSCy Schubert 		} else {
11723b9b51feSCy Schubert 			nextiph = iph->iph_next;
11733b9b51feSCy Schubert 		}
11743b9b51feSCy Schubert 
11753b9b51feSCy Schubert 		if (nextiph != NULL) {
11763b9b51feSCy Schubert 			ATOMIC_INC(nextiph->iph_ref);
11773b9b51feSCy Schubert 			token->ipt_data = nextiph;
11783b9b51feSCy Schubert 		} else {
11793b9b51feSCy Schubert 			bzero((char *)&zp, sizeof(zp));
11803b9b51feSCy Schubert 			nextiph = &zp;
11813b9b51feSCy Schubert 			token->ipt_data = NULL;
11823b9b51feSCy Schubert 		}
11833b9b51feSCy Schubert 		hnext = nextiph->iph_next;
11843b9b51feSCy Schubert 		break;
11853b9b51feSCy Schubert 
11863b9b51feSCy Schubert 	case IPFLOOKUPITER_NODE :
11873b9b51feSCy Schubert 		node = token->ipt_data;
11883b9b51feSCy Schubert 		if (node == NULL) {
11893b9b51feSCy Schubert 			iph = ipf_htable_find(arg, ilp->ili_unit,
11903b9b51feSCy Schubert 					      ilp->ili_name);
11913b9b51feSCy Schubert 			if (iph == NULL) {
11923b9b51feSCy Schubert 				IPFERROR(30009);
11933b9b51feSCy Schubert 				err = ESRCH;
11943b9b51feSCy Schubert 			} else {
11953b9b51feSCy Schubert 				nextnode = iph->iph_list;
11963b9b51feSCy Schubert 			}
11973b9b51feSCy Schubert 		} else {
11983b9b51feSCy Schubert 			nextnode = node->ipe_next;
11993b9b51feSCy Schubert 		}
12003b9b51feSCy Schubert 
12013b9b51feSCy Schubert 		if (nextnode != NULL) {
12023b9b51feSCy Schubert 			ATOMIC_INC(nextnode->ipe_ref);
12033b9b51feSCy Schubert 			token->ipt_data = nextnode;
12043b9b51feSCy Schubert 		} else {
12053b9b51feSCy Schubert 			bzero((char *)&zn, sizeof(zn));
12063b9b51feSCy Schubert 			nextnode = &zn;
12073b9b51feSCy Schubert 			token->ipt_data = NULL;
12083b9b51feSCy Schubert 		}
12093b9b51feSCy Schubert 		hnext = nextnode->ipe_next;
12103b9b51feSCy Schubert 		break;
12113b9b51feSCy Schubert 
12123b9b51feSCy Schubert 	default :
12133b9b51feSCy Schubert 		IPFERROR(30010);
12143b9b51feSCy Schubert 		err = EINVAL;
12153b9b51feSCy Schubert 		hnext = NULL;
12163b9b51feSCy Schubert 		break;
12173b9b51feSCy Schubert 	}
12183b9b51feSCy Schubert 
12193b9b51feSCy Schubert 	RWLOCK_EXIT(&softc->ipf_poolrw);
12203b9b51feSCy Schubert 	if (err != 0)
12218c82b374SCy Schubert 		return (err);
12223b9b51feSCy Schubert 
12233b9b51feSCy Schubert 	switch (ilp->ili_otype)
12243b9b51feSCy Schubert 	{
12253b9b51feSCy Schubert 	case IPFLOOKUPITER_LIST :
12263b9b51feSCy Schubert 		err = COPYOUT(nextiph, ilp->ili_data, sizeof(*nextiph));
12273b9b51feSCy Schubert 		if (err != 0) {
12283b9b51feSCy Schubert 			IPFERROR(30011);
12293b9b51feSCy Schubert 			err = EFAULT;
12303b9b51feSCy Schubert 		}
12313b9b51feSCy Schubert 		if (iph != NULL) {
12323b9b51feSCy Schubert 			WRITE_ENTER(&softc->ipf_poolrw);
12333b9b51feSCy Schubert 			ipf_htable_deref(softc, softh, iph);
12343b9b51feSCy Schubert 			RWLOCK_EXIT(&softc->ipf_poolrw);
12353b9b51feSCy Schubert 		}
12363b9b51feSCy Schubert 		break;
12373b9b51feSCy Schubert 
12383b9b51feSCy Schubert 	case IPFLOOKUPITER_NODE :
12393b9b51feSCy Schubert 		err = COPYOUT(nextnode, ilp->ili_data, sizeof(*nextnode));
12403b9b51feSCy Schubert 		if (err != 0) {
12413b9b51feSCy Schubert 			IPFERROR(30012);
12423b9b51feSCy Schubert 			err = EFAULT;
12433b9b51feSCy Schubert 		}
12443b9b51feSCy Schubert 		if (node != NULL) {
12453b9b51feSCy Schubert 			WRITE_ENTER(&softc->ipf_poolrw);
12463b9b51feSCy Schubert 			ipf_htent_deref(softc, node);
12473b9b51feSCy Schubert 			RWLOCK_EXIT(&softc->ipf_poolrw);
12483b9b51feSCy Schubert 		}
12493b9b51feSCy Schubert 		break;
12503b9b51feSCy Schubert 	}
12513b9b51feSCy Schubert 
12523b9b51feSCy Schubert 	if (hnext == NULL)
12533b9b51feSCy Schubert 		ipf_token_mark_complete(token);
12543b9b51feSCy Schubert 
12558c82b374SCy Schubert 	return (err);
12563b9b51feSCy Schubert }
12573b9b51feSCy Schubert 
12583b9b51feSCy Schubert 
12593b9b51feSCy Schubert /* ------------------------------------------------------------------------ */
12603b9b51feSCy Schubert /* Function:    ipf_htable_iter_deref                                       */
12613b9b51feSCy Schubert /* Returns:     int      - 0 = success, else  error                         */
12623b9b51feSCy Schubert /* Parameters:  softc(I) - pointer to soft context main structure           */
12633b9b51feSCy Schubert /*              arg(I)   - pointer to local context to use                  */
12643b9b51feSCy Schubert /*              otype(I) - which data structure type is being walked        */
12653b9b51feSCy Schubert /*              unit(I)  - ipfilter device to which we are working on       */
12663b9b51feSCy Schubert /*              data(I)  - pointer to old data structure                    */
12673b9b51feSCy Schubert /*                                                                          */
12683b9b51feSCy Schubert /* ------------------------------------------------------------------------ */
12693b9b51feSCy Schubert static int
ipf_htable_iter_deref(ipf_main_softc_t * softc,void * arg,int otype,int unit,void * data)1270064a5a95SCy Schubert ipf_htable_iter_deref(ipf_main_softc_t *softc, void *arg, int otype, int unit,
1271064a5a95SCy Schubert 	void *data)
12723b9b51feSCy Schubert {
12733b9b51feSCy Schubert 
12743b9b51feSCy Schubert 	if (data == NULL)
12758c82b374SCy Schubert 		return (EFAULT);
12763b9b51feSCy Schubert 
12773b9b51feSCy Schubert 	if (unit < -1 || unit > IPL_LOGMAX)
12788c82b374SCy Schubert 		return (EINVAL);
12793b9b51feSCy Schubert 
12803b9b51feSCy Schubert 	switch (otype)
12813b9b51feSCy Schubert 	{
12823b9b51feSCy Schubert 	case IPFLOOKUPITER_LIST :
12833b9b51feSCy Schubert 		ipf_htable_deref(softc, arg, (iphtable_t *)data);
12843b9b51feSCy Schubert 		break;
12853b9b51feSCy Schubert 
12863b9b51feSCy Schubert 	case IPFLOOKUPITER_NODE :
12873b9b51feSCy Schubert 		ipf_htent_deref(arg, (iphtent_t *)data);
12883b9b51feSCy Schubert 		break;
12893b9b51feSCy Schubert 	default :
12903b9b51feSCy Schubert 		break;
12913b9b51feSCy Schubert 	}
12923b9b51feSCy Schubert 
12938c82b374SCy Schubert 	return (0);
12943b9b51feSCy Schubert }
12953b9b51feSCy Schubert 
12963b9b51feSCy Schubert 
12973b9b51feSCy Schubert #ifdef USE_INET6
12983b9b51feSCy Schubert /* ------------------------------------------------------------------------ */
12993b9b51feSCy Schubert /* Function:    ipf_iphmfind6                                               */
13003b9b51feSCy Schubert /* Parameters:  iph(I)  - pointer to hash table                             */
13013b9b51feSCy Schubert /*              addr(I) - pointer to IPv6 address                           */
13023b9b51feSCy Schubert /* Locks:  ipf_poolrw                                                       */
13033b9b51feSCy Schubert /*                                                                          */
13043b9b51feSCy Schubert /* ------------------------------------------------------------------------ */
13053b9b51feSCy Schubert static iphtent_t *
ipf_iphmfind6(iphtable_t * iph,i6addr_t * addr)1306064a5a95SCy Schubert ipf_iphmfind6(iphtable_t *iph, i6addr_t *addr)
13073b9b51feSCy Schubert {
13083b9b51feSCy Schubert 	i6addr_t *msk, ips;
13093b9b51feSCy Schubert 	iphtent_t *ipe;
13103b9b51feSCy Schubert 	u_int hv;
13113b9b51feSCy Schubert 	int i;
13123b9b51feSCy Schubert 
13133b9b51feSCy Schubert 	i = 0;
13143b9b51feSCy Schubert maskloop:
13153b9b51feSCy Schubert 	msk = iph->iph_v6_masks.imt6_active + i;
13163b9b51feSCy Schubert 	ips.i6[0] = addr->i6[0] & msk->i6[0];
13173b9b51feSCy Schubert 	ips.i6[1] = addr->i6[1] & msk->i6[1];
13183b9b51feSCy Schubert 	ips.i6[2] = addr->i6[2] & msk->i6[2];
13193b9b51feSCy Schubert 	ips.i6[3] = addr->i6[3] & msk->i6[3];
13203b9b51feSCy Schubert 	hv = IPE_V6_HASH_FN(ips.i6, msk->i6, iph->iph_size);
13213b9b51feSCy Schubert 	for (ipe = iph->iph_table[hv]; (ipe != NULL); ipe = ipe->ipe_next) {
13223b9b51feSCy Schubert 		if ((ipe->ipe_family != AF_INET6) ||
13233b9b51feSCy Schubert 		    IP6_NEQ(&ipe->ipe_mask, msk) ||
13243b9b51feSCy Schubert 		    IP6_NEQ(&ipe->ipe_addr, &ips)) {
13253b9b51feSCy Schubert 			continue;
13263b9b51feSCy Schubert 		}
13273b9b51feSCy Schubert 		break;
13283b9b51feSCy Schubert 	}
13293b9b51feSCy Schubert 
13303b9b51feSCy Schubert 	if (ipe == NULL) {
13313b9b51feSCy Schubert 		i++;
13323b9b51feSCy Schubert 		if (i < iph->iph_v6_masks.imt6_max)
13333b9b51feSCy Schubert 			goto maskloop;
13343b9b51feSCy Schubert 	}
13358c82b374SCy Schubert 	return (ipe);
13363b9b51feSCy Schubert }
13373b9b51feSCy Schubert #endif
13383b9b51feSCy Schubert 
13393b9b51feSCy Schubert 
13403b9b51feSCy Schubert static void
ipf_htable_expire(ipf_main_softc_t * softc,void * arg)1341064a5a95SCy Schubert ipf_htable_expire(ipf_main_softc_t *softc, void *arg)
13423b9b51feSCy Schubert {
13433b9b51feSCy Schubert 	ipf_htable_softc_t *softh = arg;
13443b9b51feSCy Schubert 	iphtent_t *n;
13453b9b51feSCy Schubert 
13463b9b51feSCy Schubert 	while ((n = softh->ipf_node_explist) != NULL) {
13473b9b51feSCy Schubert 		if (n->ipe_die > softc->ipf_ticks)
13483b9b51feSCy Schubert 			break;
13493b9b51feSCy Schubert 
13503b9b51feSCy Schubert 		ipf_htent_remove(softc, softh, n->ipe_owner, n);
13513b9b51feSCy Schubert 	}
13523b9b51feSCy Schubert }
13533b9b51feSCy Schubert 
13543b9b51feSCy Schubert 
13553b9b51feSCy Schubert #ifndef _KERNEL
13563b9b51feSCy Schubert 
13573b9b51feSCy Schubert /* ------------------------------------------------------------------------ */
13583b9b51feSCy Schubert /*                                                                          */
13593b9b51feSCy Schubert /* ------------------------------------------------------------------------ */
13603b9b51feSCy Schubert void
ipf_htable_dump(ipf_main_softc_t * softc,void * arg)1361064a5a95SCy Schubert ipf_htable_dump(ipf_main_softc_t *softc, void *arg)
13623b9b51feSCy Schubert {
13633b9b51feSCy Schubert 	ipf_htable_softc_t *softh = arg;
13643b9b51feSCy Schubert 	iphtable_t *iph;
13653b9b51feSCy Schubert 	int i;
13663b9b51feSCy Schubert 
13673b9b51feSCy Schubert 	printf("List of configured hash tables\n");
13683b9b51feSCy Schubert 	for (i = 0; i < IPL_LOGSIZE; i++)
13693b9b51feSCy Schubert 		for (iph = softh->ipf_htables[i]; iph != NULL;
13703b9b51feSCy Schubert 		     iph = iph->iph_next)
13713b9b51feSCy Schubert 			printhash(iph, bcopywrap, NULL, opts, NULL);
13723b9b51feSCy Schubert 
13733b9b51feSCy Schubert }
13743b9b51feSCy Schubert #endif
1375