17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * Copyright (C) 1993-2001, 2003 by Darren Reed.
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * See the IPFILTER.LICENCE file for details on licencing.
57c478bd9Sstevel@tonic-gate  *
6*de22af4eSJohn Ojemann  * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
77c478bd9Sstevel@tonic-gate  */
87c478bd9Sstevel@tonic-gate 
97c478bd9Sstevel@tonic-gate #if defined(KERNEL) || defined(_KERNEL)
107c478bd9Sstevel@tonic-gate # undef KERNEL
117c478bd9Sstevel@tonic-gate # undef _KERNEL
127c478bd9Sstevel@tonic-gate # define        KERNEL	1
137c478bd9Sstevel@tonic-gate # define        _KERNEL	1
147c478bd9Sstevel@tonic-gate #endif
157c478bd9Sstevel@tonic-gate #include <sys/param.h>
167c478bd9Sstevel@tonic-gate #include <sys/types.h>
177c478bd9Sstevel@tonic-gate #include <sys/errno.h>
187c478bd9Sstevel@tonic-gate #include <sys/time.h>
197c478bd9Sstevel@tonic-gate #include <sys/file.h>
207c478bd9Sstevel@tonic-gate #if !defined(_KERNEL)
217c478bd9Sstevel@tonic-gate # include <stdlib.h>
227c478bd9Sstevel@tonic-gate # include <string.h>
237c478bd9Sstevel@tonic-gate # define _KERNEL
247c478bd9Sstevel@tonic-gate # ifdef __OpenBSD__
257c478bd9Sstevel@tonic-gate struct file;
267c478bd9Sstevel@tonic-gate # endif
277c478bd9Sstevel@tonic-gate # include <sys/uio.h>
287c478bd9Sstevel@tonic-gate # undef _KERNEL
297c478bd9Sstevel@tonic-gate #endif
307c478bd9Sstevel@tonic-gate #include <sys/socket.h>
317c478bd9Sstevel@tonic-gate #if defined(__FreeBSD_version) && (__FreeBSD_version >= 300000)
327c478bd9Sstevel@tonic-gate # include <sys/malloc.h>
337c478bd9Sstevel@tonic-gate #endif
347c478bd9Sstevel@tonic-gate #if defined(__FreeBSD__)
357c478bd9Sstevel@tonic-gate #  include <sys/cdefs.h>
367c478bd9Sstevel@tonic-gate #  include <sys/proc.h>
377c478bd9Sstevel@tonic-gate #endif
38ab25eeb5Syz #if !defined(__svr4__) && !defined(__SVR4) && !defined(__hpux) && \
39ab25eeb5Syz     !defined(linux)
407c478bd9Sstevel@tonic-gate # include <sys/mbuf.h>
417c478bd9Sstevel@tonic-gate #endif
427c478bd9Sstevel@tonic-gate #if defined(_KERNEL)
437c478bd9Sstevel@tonic-gate # include <sys/systm.h>
447c478bd9Sstevel@tonic-gate #else
457c478bd9Sstevel@tonic-gate # include <stdio.h>
467c478bd9Sstevel@tonic-gate #endif
477c478bd9Sstevel@tonic-gate #include <netinet/in.h>
487c478bd9Sstevel@tonic-gate #include <net/if.h>
497c478bd9Sstevel@tonic-gate 
507c478bd9Sstevel@tonic-gate #include "netinet/ip_compat.h"
517c478bd9Sstevel@tonic-gate #include "netinet/ip_fil.h"
527c478bd9Sstevel@tonic-gate #include "netinet/ip_lookup.h"
537c478bd9Sstevel@tonic-gate #include "netinet/ip_htable.h"
54f4b3ec61Sdh #include "netinet/ipf_stack.h"
55ab25eeb5Syz /* END OF INCLUDES */
567c478bd9Sstevel@tonic-gate 
577c478bd9Sstevel@tonic-gate #if !defined(lint)
58ab25eeb5Syz static const char rcsid[] = "@(#)$Id: ip_htable.c,v 2.34.2.3 2005/05/14 05:11:38 darrenr Exp $";
597c478bd9Sstevel@tonic-gate #endif
607c478bd9Sstevel@tonic-gate 
617c478bd9Sstevel@tonic-gate #ifdef	IPFILTER_LOOKUP
627c478bd9Sstevel@tonic-gate static iphtent_t *fr_iphmfind __P((iphtable_t *, struct in_addr *));
637663b816Sml #ifdef USE_INET6
647663b816Sml static iphtent_t *fr_iphmfind6 __P((iphtable_t *, struct in6_addr *));
657663b816Sml static uint32_t sum4(uint32_t *);
667663b816Sml static void left_shift_ipv6 __P((char *));
677663b816Sml #endif
687c478bd9Sstevel@tonic-gate 
fr_htable_unload(ifs)69f4b3ec61Sdh void fr_htable_unload(ifs)
70f4b3ec61Sdh ipf_stack_t *ifs;
717c478bd9Sstevel@tonic-gate {
727c478bd9Sstevel@tonic-gate 	iplookupflush_t fop;
73ab25eeb5Syz 
74ab25eeb5Syz 	fop.iplf_unit = IPL_LOGALL;
75f4b3ec61Sdh 	(void)fr_flushhtable(&fop, ifs);
767c478bd9Sstevel@tonic-gate }
777c478bd9Sstevel@tonic-gate 
78ab25eeb5Syz 
fr_gethtablestat(op,ifs)79f4b3ec61Sdh int fr_gethtablestat(op, ifs)
807663b816Sml iplookupop_t *op;
81f4b3ec61Sdh ipf_stack_t *ifs;
827663b816Sml {
837663b816Sml 	iphtstat_t stats;
847663b816Sml 
857663b816Sml 	if (op->iplo_size != sizeof(stats))
867663b816Sml 		return EINVAL;
877663b816Sml 
88f4b3ec61Sdh 	stats.iphs_tables = ifs->ifs_ipf_htables[op->iplo_unit];
89f4b3ec61Sdh 	stats.iphs_numtables = ifs->ifs_ipf_nhtables[op->iplo_unit];
90f4b3ec61Sdh 	stats.iphs_numnodes = ifs->ifs_ipf_nhtnodes[op->iplo_unit];
91f4b3ec61Sdh 	stats.iphs_nomem = ifs->ifs_ipht_nomem[op->iplo_unit];
927663b816Sml 
937663b816Sml 	return COPYOUT(&stats, op->iplo_struct, sizeof(stats));
947663b816Sml 
957663b816Sml }
967663b816Sml 
977c478bd9Sstevel@tonic-gate 
987c478bd9Sstevel@tonic-gate /*
997c478bd9Sstevel@tonic-gate  * Create a new hash table using the template passed.
1007c478bd9Sstevel@tonic-gate  */
fr_newhtable(op,ifs)101f4b3ec61Sdh int fr_newhtable(op, ifs)
1027c478bd9Sstevel@tonic-gate iplookupop_t *op;
103f4b3ec61Sdh ipf_stack_t *ifs;
1047c478bd9Sstevel@tonic-gate {
1057c478bd9Sstevel@tonic-gate 	iphtable_t *iph, *oiph;
1067c478bd9Sstevel@tonic-gate 	char name[FR_GROUPLEN];
1077c478bd9Sstevel@tonic-gate 	int err, i, unit;
1087c478bd9Sstevel@tonic-gate 
1097c478bd9Sstevel@tonic-gate 	KMALLOC(iph, iphtable_t *);
110ab25eeb5Syz 	if (iph == NULL) {
111f4b3ec61Sdh 		ifs->ifs_ipht_nomem[op->iplo_unit]++;
112ab25eeb5Syz 		return ENOMEM;
113ab25eeb5Syz 	}
1147c478bd9Sstevel@tonic-gate 
1157c478bd9Sstevel@tonic-gate 	err = COPYIN(op->iplo_struct, iph, sizeof(*iph));
1167c478bd9Sstevel@tonic-gate 	if (err != 0) {
1177c478bd9Sstevel@tonic-gate 		KFREE(iph);
1187c478bd9Sstevel@tonic-gate 		return EFAULT;
1197c478bd9Sstevel@tonic-gate 	}
1207c478bd9Sstevel@tonic-gate 
1217c478bd9Sstevel@tonic-gate 	unit = op->iplo_unit;
1227c478bd9Sstevel@tonic-gate 	if (iph->iph_unit != unit) {
1237c478bd9Sstevel@tonic-gate 		KFREE(iph);
1247c478bd9Sstevel@tonic-gate 		return EINVAL;
1257c478bd9Sstevel@tonic-gate 	}
1267c478bd9Sstevel@tonic-gate 
1277c478bd9Sstevel@tonic-gate 	if ((op->iplo_arg & IPHASH_ANON) == 0) {
128f4b3ec61Sdh 		if (fr_findhtable(op->iplo_unit, op->iplo_name, ifs) != NULL) {
1297c478bd9Sstevel@tonic-gate 			KFREE(iph);
1307c478bd9Sstevel@tonic-gate 			return EEXIST;
1317c478bd9Sstevel@tonic-gate 		}
1327c478bd9Sstevel@tonic-gate 	} else {
1337c478bd9Sstevel@tonic-gate 		i = IPHASH_ANON;
1347c478bd9Sstevel@tonic-gate 		do {
1357c478bd9Sstevel@tonic-gate 			i++;
136ab25eeb5Syz #if defined(SNPRINTF) && defined(_KERNEL)
137ab25eeb5Syz 			(void)SNPRINTF(name, sizeof(name), "%u", i);
138ab25eeb5Syz #else
1397c478bd9Sstevel@tonic-gate 			(void)sprintf(name, "%u", i);
140ab25eeb5Syz #endif
141f4b3ec61Sdh 			for (oiph = ifs->ifs_ipf_htables[unit]; oiph != NULL;
1427c478bd9Sstevel@tonic-gate 			     oiph = oiph->iph_next)
1437c478bd9Sstevel@tonic-gate 				if (strncmp(oiph->iph_name, name,
1447c478bd9Sstevel@tonic-gate 					    sizeof(oiph->iph_name)) == 0)
1457c478bd9Sstevel@tonic-gate 					break;
1467c478bd9Sstevel@tonic-gate 		} while (oiph != NULL);
1477c478bd9Sstevel@tonic-gate 		(void)strncpy(iph->iph_name, name, sizeof(iph->iph_name));
1487c478bd9Sstevel@tonic-gate 		err = COPYOUT(iph, op->iplo_struct, sizeof(*iph));
1497c478bd9Sstevel@tonic-gate 		if (err != 0) {
1507c478bd9Sstevel@tonic-gate 			KFREE(iph);
1517c478bd9Sstevel@tonic-gate 			return EFAULT;
1527c478bd9Sstevel@tonic-gate 		}
1537c478bd9Sstevel@tonic-gate 		iph->iph_type |= IPHASH_ANON;
1547c478bd9Sstevel@tonic-gate 	}
1557c478bd9Sstevel@tonic-gate 
1567c478bd9Sstevel@tonic-gate 	KMALLOCS(iph->iph_table, iphtent_t **,
1577c478bd9Sstevel@tonic-gate 		 iph->iph_size * sizeof(*iph->iph_table));
1587c478bd9Sstevel@tonic-gate 	if (iph->iph_table == NULL) {
1597c478bd9Sstevel@tonic-gate 		KFREE(iph);
160f4b3ec61Sdh 		ifs->ifs_ipht_nomem[unit]++;
1617c478bd9Sstevel@tonic-gate 		return ENOMEM;
1627c478bd9Sstevel@tonic-gate 	}
1637c478bd9Sstevel@tonic-gate 
1647c478bd9Sstevel@tonic-gate 	bzero((char *)iph->iph_table, iph->iph_size * sizeof(*iph->iph_table));
1657663b816Sml 	iph->iph_masks[0] = 0;
1667663b816Sml 	iph->iph_masks[1] = 0;
1677663b816Sml 	iph->iph_masks[2] = 0;
1687663b816Sml 	iph->iph_masks[3] = 0;
169f4b3ec61Sdh 	iph->iph_list = NULL;
1707c478bd9Sstevel@tonic-gate 
171f4b3ec61Sdh 	iph->iph_ref = 1;
172f4b3ec61Sdh 	iph->iph_next = ifs->ifs_ipf_htables[unit];
173f4b3ec61Sdh 	iph->iph_pnext = &ifs->ifs_ipf_htables[unit];
174f4b3ec61Sdh 	if (ifs->ifs_ipf_htables[unit] != NULL)
175f4b3ec61Sdh 		ifs->ifs_ipf_htables[unit]->iph_pnext = &iph->iph_next;
176f4b3ec61Sdh 	ifs->ifs_ipf_htables[unit] = iph;
1777663b816Sml 
178f4b3ec61Sdh 	ifs->ifs_ipf_nhtables[unit]++;
1797663b816Sml 
1807c478bd9Sstevel@tonic-gate 	return 0;
1817c478bd9Sstevel@tonic-gate }
1827c478bd9Sstevel@tonic-gate 
1837c478bd9Sstevel@tonic-gate 
1847c478bd9Sstevel@tonic-gate /*
1857c478bd9Sstevel@tonic-gate  */
fr_removehtable(op,ifs)186f4b3ec61Sdh int fr_removehtable(op, ifs)
1877c478bd9Sstevel@tonic-gate iplookupop_t *op;
188f4b3ec61Sdh ipf_stack_t *ifs;
1897c478bd9Sstevel@tonic-gate {
1907c478bd9Sstevel@tonic-gate 	iphtable_t *iph;
1917c478bd9Sstevel@tonic-gate 
1927c478bd9Sstevel@tonic-gate 
193f4b3ec61Sdh 	iph = fr_findhtable(op->iplo_unit, op->iplo_name, ifs);
1947c478bd9Sstevel@tonic-gate 	if (iph == NULL)
1957c478bd9Sstevel@tonic-gate 		return ESRCH;
1967c478bd9Sstevel@tonic-gate 
1977c478bd9Sstevel@tonic-gate 	if (iph->iph_unit != op->iplo_unit) {
1987c478bd9Sstevel@tonic-gate 		return EINVAL;
1997c478bd9Sstevel@tonic-gate 	}
200f4b3ec61Sdh 
201f4b3ec61Sdh 	if (iph->iph_ref != 1) {
2027c478bd9Sstevel@tonic-gate 		return EBUSY;
2037c478bd9Sstevel@tonic-gate 	}
2047c478bd9Sstevel@tonic-gate 
205f4b3ec61Sdh 	fr_delhtable(iph, ifs);
2067c478bd9Sstevel@tonic-gate 
2077c478bd9Sstevel@tonic-gate 	return 0;
2087c478bd9Sstevel@tonic-gate }
2097c478bd9Sstevel@tonic-gate 
2107c478bd9Sstevel@tonic-gate 
fr_delhtable(iph,ifs)211f4b3ec61Sdh void fr_delhtable(iph, ifs)
2127c478bd9Sstevel@tonic-gate iphtable_t *iph;
213f4b3ec61Sdh ipf_stack_t *ifs;
2147c478bd9Sstevel@tonic-gate {
215ab25eeb5Syz 	iphtent_t *ipe;
216ab25eeb5Syz 	int i;
217ab25eeb5Syz 
218ab25eeb5Syz 	for (i = 0; i < iph->iph_size; i++)
219ab25eeb5Syz 		while ((ipe = iph->iph_table[i]) != NULL)
220f4b3ec61Sdh 			if (fr_delhtent(iph, ipe, ifs) != 0)
221ab25eeb5Syz 				return;
2227c478bd9Sstevel@tonic-gate 
2237c478bd9Sstevel@tonic-gate 	*iph->iph_pnext = iph->iph_next;
2247c478bd9Sstevel@tonic-gate 	if (iph->iph_next != NULL)
2257c478bd9Sstevel@tonic-gate 		iph->iph_next->iph_pnext = iph->iph_pnext;
2267c478bd9Sstevel@tonic-gate 
227f4b3ec61Sdh 	ifs->ifs_ipf_nhtables[iph->iph_unit]--;
228ab25eeb5Syz 
229f4b3ec61Sdh 	if (iph->iph_ref == 1) {
230ab25eeb5Syz 		KFREES(iph->iph_table, iph->iph_size * sizeof(*iph->iph_table));
231ab25eeb5Syz 		KFREE(iph);
232ab25eeb5Syz 	}
2337c478bd9Sstevel@tonic-gate }
2347c478bd9Sstevel@tonic-gate 
2357c478bd9Sstevel@tonic-gate 
fr_derefhtable(iph,ifs)236f4b3ec61Sdh void fr_derefhtable(iph, ifs)
2377c478bd9Sstevel@tonic-gate iphtable_t *iph;
238f4b3ec61Sdh ipf_stack_t *ifs;
2397c478bd9Sstevel@tonic-gate {
2407c478bd9Sstevel@tonic-gate 	iph->iph_ref--;
2417c478bd9Sstevel@tonic-gate 	if (iph->iph_ref == 0)
242f4b3ec61Sdh 		fr_delhtable(iph, ifs);
243f4b3ec61Sdh }
244f4b3ec61Sdh 
245f4b3ec61Sdh 
fr_derefhtent(ipe)246f4b3ec61Sdh void fr_derefhtent(ipe)
247f4b3ec61Sdh iphtent_t *ipe;
248f4b3ec61Sdh {
249f4b3ec61Sdh 	ipe->ipe_ref--;
250f4b3ec61Sdh 	if (ipe->ipe_ref == 0) {
251f4b3ec61Sdh 		KFREE(ipe);
252f4b3ec61Sdh 	}
2537c478bd9Sstevel@tonic-gate }
2547c478bd9Sstevel@tonic-gate 
2557c478bd9Sstevel@tonic-gate 
fr_findhtable(unit,name,ifs)256f4b3ec61Sdh iphtable_t *fr_findhtable(unit, name, ifs)
2577c478bd9Sstevel@tonic-gate int unit;
2587c478bd9Sstevel@tonic-gate char *name;
259f4b3ec61Sdh ipf_stack_t *ifs;
2607c478bd9Sstevel@tonic-gate {
2617c478bd9Sstevel@tonic-gate 	iphtable_t *iph;
2627c478bd9Sstevel@tonic-gate 
263f4b3ec61Sdh 	for (iph = ifs->ifs_ipf_htables[unit]; iph != NULL; iph = iph->iph_next)
2647c478bd9Sstevel@tonic-gate 		if (strncmp(iph->iph_name, name, sizeof(iph->iph_name)) == 0)
2657c478bd9Sstevel@tonic-gate 			break;
2667c478bd9Sstevel@tonic-gate 	return iph;
2677c478bd9Sstevel@tonic-gate }
2687c478bd9Sstevel@tonic-gate 
2697c478bd9Sstevel@tonic-gate 
fr_flushhtable(op,ifs)270f4b3ec61Sdh size_t fr_flushhtable(op, ifs)
2717c478bd9Sstevel@tonic-gate iplookupflush_t *op;
272f4b3ec61Sdh ipf_stack_t *ifs;
2737c478bd9Sstevel@tonic-gate {
2747c478bd9Sstevel@tonic-gate 	iphtable_t *iph;
275ab25eeb5Syz 	size_t freed;
276ab25eeb5Syz 	int i;
2777c478bd9Sstevel@tonic-gate 
2787c478bd9Sstevel@tonic-gate 	freed = 0;
2797c478bd9Sstevel@tonic-gate 
280ab25eeb5Syz 	for (i = 0; i <= IPL_LOGMAX; i++) {
281ab25eeb5Syz 		if (op->iplf_unit == i || op->iplf_unit == IPL_LOGALL) {
282f4b3ec61Sdh 			while ((iph = ifs->ifs_ipf_htables[i]) != NULL) {
283f4b3ec61Sdh 				fr_delhtable(iph, ifs);
284ab25eeb5Syz 				freed++;
2857c478bd9Sstevel@tonic-gate 			}
2867c478bd9Sstevel@tonic-gate 		}
287ab25eeb5Syz 	}
2887c478bd9Sstevel@tonic-gate 
2897c478bd9Sstevel@tonic-gate 	return freed;
2907c478bd9Sstevel@tonic-gate }
2917c478bd9Sstevel@tonic-gate 
2927c478bd9Sstevel@tonic-gate 
2937c478bd9Sstevel@tonic-gate /*
2947c478bd9Sstevel@tonic-gate  * Add an entry to a hash table.
2957c478bd9Sstevel@tonic-gate  */
fr_addhtent(iph,ipeo,ifs)296f4b3ec61Sdh int fr_addhtent(iph, ipeo, ifs)
2977c478bd9Sstevel@tonic-gate iphtable_t *iph;
2987c478bd9Sstevel@tonic-gate iphtent_t *ipeo;
299f4b3ec61Sdh ipf_stack_t *ifs;
3007c478bd9Sstevel@tonic-gate {
3017c478bd9Sstevel@tonic-gate 	iphtent_t *ipe;
3027c478bd9Sstevel@tonic-gate 	u_int hv;
3037c478bd9Sstevel@tonic-gate 	int bits;
3047c478bd9Sstevel@tonic-gate 
3057c478bd9Sstevel@tonic-gate 	KMALLOC(ipe, iphtent_t *);
3067c478bd9Sstevel@tonic-gate 	if (ipe == NULL)
3077c478bd9Sstevel@tonic-gate 		return -1;
3087c478bd9Sstevel@tonic-gate 
3097c478bd9Sstevel@tonic-gate 	bcopy((char *)ipeo, (char *)ipe, sizeof(*ipe));
3107663b816Sml #ifdef USE_INET6
3117663b816Sml 	if (ipe->ipe_family == AF_INET6) {
3127663b816Sml 		bits = count6bits((u_32_t *)ipe->ipe_mask.in6_addr8);
3137663b816Sml 		hv = IPE_HASH_FN(sum4((uint32_t *)ipe->ipe_addr.in6_addr8),
3147663b816Sml 				 sum4((uint32_t *)ipe->ipe_mask.in6_addr8),
3157663b816Sml 				 iph->iph_size);
3167663b816Sml 	} else
3177663b816Sml #endif
3187663b816Sml 	if (ipe->ipe_family == AF_INET)
3197663b816Sml 	{
3207663b816Sml 		ipe->ipe_addr.in4_addr &= ipe->ipe_mask.in4_addr;
3217663b816Sml 		ipe->ipe_addr.in4_addr = ntohl(ipe->ipe_addr.in4_addr);
3227663b816Sml 		bits = count4bits(ipe->ipe_mask.in4_addr);
3237663b816Sml 		ipe->ipe_mask.in4_addr = ntohl(ipe->ipe_mask.in4_addr);
3247663b816Sml 
3257663b816Sml 		hv = IPE_HASH_FN(ipe->ipe_addr.in4_addr, ipe->ipe_mask.in4_addr,
3267663b816Sml 				 iph->iph_size);
3277663b816Sml 	} else
3287663b816Sml 		return -1;
3297c478bd9Sstevel@tonic-gate 
330f4b3ec61Sdh 	ipe->ipe_ref = 1;
3317c478bd9Sstevel@tonic-gate 	ipe->ipe_next = iph->iph_table[hv];
3327c478bd9Sstevel@tonic-gate 	ipe->ipe_pnext = iph->iph_table + hv;
3337c478bd9Sstevel@tonic-gate 
3347c478bd9Sstevel@tonic-gate 	if (iph->iph_table[hv] != NULL)
3357c478bd9Sstevel@tonic-gate 		iph->iph_table[hv]->ipe_pnext = &ipe->ipe_next;
3367c478bd9Sstevel@tonic-gate 	iph->iph_table[hv] = ipe;
337f4b3ec61Sdh 
338f4b3ec61Sdh 	ipe->ipe_snext = iph->iph_list;
339f4b3ec61Sdh 	ipe->ipe_psnext = &iph->iph_list;
340f4b3ec61Sdh 	if (ipe->ipe_next != NULL)
341f4b3ec61Sdh 		ipe->ipe_next->ipe_psnext = &ipe->ipe_snext;
342f4b3ec61Sdh 	iph->iph_list = ipe;
343f4b3ec61Sdh 
3447663b816Sml #ifdef USE_INET6
3457663b816Sml 	if (ipe->ipe_family == AF_INET6) {
3467663b816Sml 		if ((bits >= 0) && (bits != 128))
3477663b816Sml 			if (bits >= 96)
3487663b816Sml 				iph->iph_masks[0] |= 1 << (bits - 96);
3497663b816Sml 			else if (bits >= 64)
3507663b816Sml 				iph->iph_masks[1] |= 1 << (bits - 64);
3517663b816Sml 			else if (bits >= 32)
3527663b816Sml 				iph->iph_masks[2] |= 1 << (bits - 32);
3537663b816Sml 			else
3547663b816Sml 				iph->iph_masks[3] |= 1 << bits;
3557663b816Sml 
3567663b816Sml 	} else
3577663b816Sml #endif
3587663b816Sml 	{
3597663b816Sml 		if ((bits >= 0) && (bits != 32))
3607663b816Sml 			iph->iph_masks[3] |= 1 << bits;
3617663b816Sml 	}
3627c478bd9Sstevel@tonic-gate 
3637c478bd9Sstevel@tonic-gate 	switch (iph->iph_type & ~IPHASH_ANON)
3647c478bd9Sstevel@tonic-gate 	{
3657c478bd9Sstevel@tonic-gate 	case IPHASH_GROUPMAP :
3667c478bd9Sstevel@tonic-gate 		ipe->ipe_ptr = fr_addgroup(ipe->ipe_group, NULL,
3677c478bd9Sstevel@tonic-gate 					   iph->iph_flags, IPL_LOGIPF,
368f4b3ec61Sdh 					   ifs->ifs_fr_active, ifs);
3697c478bd9Sstevel@tonic-gate 		break;
3707c478bd9Sstevel@tonic-gate 
3717c478bd9Sstevel@tonic-gate 	default :
3727c478bd9Sstevel@tonic-gate 		ipe->ipe_ptr = NULL;
3737c478bd9Sstevel@tonic-gate 		ipe->ipe_value = 0;
3747c478bd9Sstevel@tonic-gate 		break;
3757c478bd9Sstevel@tonic-gate 	}
3767c478bd9Sstevel@tonic-gate 
377f4b3ec61Sdh 	ifs->ifs_ipf_nhtnodes[iph->iph_unit]++;
3787663b816Sml 
3797c478bd9Sstevel@tonic-gate 	return 0;
3807c478bd9Sstevel@tonic-gate }
3817c478bd9Sstevel@tonic-gate 
3827c478bd9Sstevel@tonic-gate 
3837c478bd9Sstevel@tonic-gate /*
3847c478bd9Sstevel@tonic-gate  * Delete an entry from a hash table.
3857c478bd9Sstevel@tonic-gate  */
fr_delhtent(iph,ipe,ifs)386f4b3ec61Sdh int fr_delhtent(iph, ipe, ifs)
3877c478bd9Sstevel@tonic-gate iphtable_t *iph;
3887c478bd9Sstevel@tonic-gate iphtent_t *ipe;
389f4b3ec61Sdh ipf_stack_t *ifs;
3907c478bd9Sstevel@tonic-gate {
391f4b3ec61Sdh 	if (ipe->ipe_ref != 1)
3927c478bd9Sstevel@tonic-gate 		return EBUSY;
3937c478bd9Sstevel@tonic-gate 
3947c478bd9Sstevel@tonic-gate 
3957c478bd9Sstevel@tonic-gate 	*ipe->ipe_pnext = ipe->ipe_next;
3967c478bd9Sstevel@tonic-gate 	if (ipe->ipe_next != NULL)
3977c478bd9Sstevel@tonic-gate 		ipe->ipe_next->ipe_pnext = ipe->ipe_pnext;
3987c478bd9Sstevel@tonic-gate 
3997c478bd9Sstevel@tonic-gate 	switch (iph->iph_type & ~IPHASH_ANON)
4007c478bd9Sstevel@tonic-gate 	{
4017c478bd9Sstevel@tonic-gate 	case IPHASH_GROUPMAP :
4027c478bd9Sstevel@tonic-gate 		if (ipe->ipe_group != NULL)
403f4b3ec61Sdh 			fr_delgroup(ipe->ipe_group, IPL_LOGIPF,
404f4b3ec61Sdh 				    ifs->ifs_fr_active, ifs);
4057c478bd9Sstevel@tonic-gate 		break;
4067c478bd9Sstevel@tonic-gate 
4077c478bd9Sstevel@tonic-gate 	default :
4087c478bd9Sstevel@tonic-gate 		ipe->ipe_ptr = NULL;
4097c478bd9Sstevel@tonic-gate 		ipe->ipe_value = 0;
4107c478bd9Sstevel@tonic-gate 		break;
4117c478bd9Sstevel@tonic-gate 	}
4127c478bd9Sstevel@tonic-gate 
4137c478bd9Sstevel@tonic-gate 	KFREE(ipe);
4147c478bd9Sstevel@tonic-gate 
415f4b3ec61Sdh 	ifs->ifs_ipf_nhtnodes[iph->iph_unit]--;
416f4b3ec61Sdh 
4177c478bd9Sstevel@tonic-gate 	return 0;
4187c478bd9Sstevel@tonic-gate }
4197c478bd9Sstevel@tonic-gate 
4207c478bd9Sstevel@tonic-gate 
fr_iphmfindgroup(tptr,version,aptr,ifs)421f4b3ec61Sdh void *fr_iphmfindgroup(tptr, version, aptr, ifs)
422ab25eeb5Syz void *tptr;
4237663b816Sml int version;
424ab25eeb5Syz void *aptr;
425f4b3ec61Sdh ipf_stack_t *ifs;
4267c478bd9Sstevel@tonic-gate {
4277663b816Sml 	i6addr_t *addr;
4287c478bd9Sstevel@tonic-gate 	iphtable_t *iph;
4297c478bd9Sstevel@tonic-gate 	iphtent_t *ipe;
4307c478bd9Sstevel@tonic-gate 	void *rval;
4317c478bd9Sstevel@tonic-gate 
4327663b816Sml 	if ((version != 4)
4337663b816Sml #ifdef USE_INET6
4347663b816Sml 	    && (version != 6)
4357663b816Sml #endif
4367663b816Sml 	    )
4377663b816Sml 		return NULL;
4387663b816Sml 
439f4b3ec61Sdh 	READ_ENTER(&ifs->ifs_ip_poolrw);
4407c478bd9Sstevel@tonic-gate 	iph = tptr;
4417c478bd9Sstevel@tonic-gate 	addr = aptr;
4427c478bd9Sstevel@tonic-gate 
4437663b816Sml #ifdef USE_INET6
4447663b816Sml 	if (version == 6)
4457663b816Sml 		ipe = fr_iphmfind6(iph, &addr->in6);
4467663b816Sml 	else
4477663b816Sml #endif
4487663b816Sml 	if (version == 4)
4497663b816Sml 		ipe = fr_iphmfind(iph, &addr->in4);
4507663b816Sml 	else
4517663b816Sml 		ipe = NULL;
4527c478bd9Sstevel@tonic-gate 	if (ipe != NULL)
4537c478bd9Sstevel@tonic-gate 		rval = ipe->ipe_ptr;
4547c478bd9Sstevel@tonic-gate 	else
4557c478bd9Sstevel@tonic-gate 		rval = NULL;
456f4b3ec61Sdh 	RWLOCK_EXIT(&ifs->ifs_ip_poolrw);
4577c478bd9Sstevel@tonic-gate 	return rval;
4587c478bd9Sstevel@tonic-gate }
4597c478bd9Sstevel@tonic-gate 
4607c478bd9Sstevel@tonic-gate 
461ab25eeb5Syz /* ------------------------------------------------------------------------ */
462ab25eeb5Syz /* Function:    fr_iphmfindip                                               */
463ab25eeb5Syz /* Returns:     int     - 0 == +ve match, -1 == error, 1 == -ve/no match    */
464ab25eeb5Syz /* Parameters:  tptr(I)    - pointer to the pool to search                  */
465ab25eeb5Syz /*              version(I) - IP protocol version (4 or 6)                   */
466ab25eeb5Syz /*              aptr(I)    - pointer to address information                 */
467*de22af4eSJohn Ojemann /*		fin	   - pointer to packet information		    */
468*de22af4eSJohn Ojemann /*		ifs	   - ipf stack instance				    */
469ab25eeb5Syz /*                                                                          */
470ab25eeb5Syz /* Search the hash table for a given address and return a search result.    */
471ab25eeb5Syz /* ------------------------------------------------------------------------ */
fr_iphmfindip(tptr,version,aptr,fin,ifs)472*de22af4eSJohn Ojemann int fr_iphmfindip(tptr, version, aptr, fin, ifs)
4737c478bd9Sstevel@tonic-gate void *tptr, *aptr;
4747c478bd9Sstevel@tonic-gate int version;
475*de22af4eSJohn Ojemann fr_info_t *fin;
476f4b3ec61Sdh ipf_stack_t *ifs;
4777c478bd9Sstevel@tonic-gate {
4787663b816Sml 	i6addr_t *addr;
4797c478bd9Sstevel@tonic-gate 	iphtable_t *iph;
4807c478bd9Sstevel@tonic-gate 	iphtent_t *ipe;
4817c478bd9Sstevel@tonic-gate 	int rval;
4827c478bd9Sstevel@tonic-gate 
483ab25eeb5Syz 	if ((version != 4)
484ab25eeb5Syz #ifdef USE_INET6
485ab25eeb5Syz 	    && (version != 6)
486ab25eeb5Syz #endif
487ab25eeb5Syz 	    )
488ab25eeb5Syz 		return -1;
489ab25eeb5Syz 
4907c478bd9Sstevel@tonic-gate 	if (tptr == NULL || aptr == NULL)
491ab25eeb5Syz 		return -1;
4927c478bd9Sstevel@tonic-gate 
4937c478bd9Sstevel@tonic-gate 	iph = tptr;
4947c478bd9Sstevel@tonic-gate 	addr = aptr;
4957c478bd9Sstevel@tonic-gate 
496f4b3ec61Sdh 	READ_ENTER(&ifs->ifs_ip_poolrw);
4977663b816Sml #ifdef USE_INET6
4987663b816Sml 	if (version == 6)
4997663b816Sml 		ipe = fr_iphmfind6(iph, &addr->in6);
5007663b816Sml 	else
5017663b816Sml #endif
5027663b816Sml 	if (version == 4)
5037663b816Sml 		ipe = fr_iphmfind(iph, &addr->in4);
5047663b816Sml 	else
5057663b816Sml 		ipe = NULL;
506*de22af4eSJohn Ojemann 	if (ipe != NULL) {
507*de22af4e