1/*
2 * Copyright (C) 1993-2001, 2003 by Darren Reed.
3 *
4 * See the IPFILTER.LICENCE file for details on licencing.
5 *
6 * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
7 */
8
9#if defined(KERNEL) || defined(_KERNEL)
10# undef KERNEL
11# undef _KERNEL
12# define        KERNEL	1
13# define        _KERNEL	1
14#endif
15#include <sys/param.h>
16#include <sys/types.h>
17#include <sys/errno.h>
18#include <sys/time.h>
19#include <sys/file.h>
20#if !defined(_KERNEL)
21# include <stdlib.h>
22# include <string.h>
23# define _KERNEL
24# ifdef __OpenBSD__
25struct file;
26# endif
27# include <sys/uio.h>
28# undef _KERNEL
29#endif
30#include <sys/socket.h>
31#if defined(__FreeBSD_version) && (__FreeBSD_version >= 300000)
32# include <sys/malloc.h>
33#endif
34#if defined(__FreeBSD__)
35#  include <sys/cdefs.h>
36#  include <sys/proc.h>
37#endif
38#if !defined(__svr4__) && !defined(__SVR4) && !defined(__hpux) && \
39    !defined(linux)
40# include <sys/mbuf.h>
41#endif
42#if defined(_KERNEL)
43# include <sys/systm.h>
44#else
45# include <stdio.h>
46#endif
47#include <netinet/in.h>
48#include <net/if.h>
49
50#include "netinet/ip_compat.h"
51#include "netinet/ip_fil.h"
52#include "netinet/ip_lookup.h"
53#include "netinet/ip_htable.h"
54#include "netinet/ipf_stack.h"
55/* END OF INCLUDES */
56
57#if !defined(lint)
58static const char rcsid[] = "@(#)$Id: ip_htable.c,v 2.34.2.3 2005/05/14 05:11:38 darrenr Exp $";
59#endif
60
61#ifdef	IPFILTER_LOOKUP
62static iphtent_t *fr_iphmfind __P((iphtable_t *, struct in_addr *));
63#ifdef USE_INET6
64static iphtent_t *fr_iphmfind6 __P((iphtable_t *, struct in6_addr *));
65static uint32_t sum4(uint32_t *);
66static void left_shift_ipv6 __P((char *));
67#endif
68
69void fr_htable_unload(ifs)
70ipf_stack_t *ifs;
71{
72	iplookupflush_t fop;
73
74	fop.iplf_unit = IPL_LOGALL;
75	(void)fr_flushhtable(&fop, ifs);
76}
77
78
79int fr_gethtablestat(op, ifs)
80iplookupop_t *op;
81ipf_stack_t *ifs;
82{
83	iphtstat_t stats;
84
85	if (op->iplo_size != sizeof(stats))
86		return EINVAL;
87
88	stats.iphs_tables = ifs->ifs_ipf_htables[op->iplo_unit];
89	stats.iphs_numtables = ifs->ifs_ipf_nhtables[op->iplo_unit];
90	stats.iphs_numnodes = ifs->ifs_ipf_nhtnodes[op->iplo_unit];
91	stats.iphs_nomem = ifs->ifs_ipht_nomem[op->iplo_unit];
92
93	return COPYOUT(&stats, op->iplo_struct, sizeof(stats));
94
95}
96
97
98/*
99 * Create a new hash table using the template passed.
100 */
101int fr_newhtable(op, ifs)
102iplookupop_t *op;
103ipf_stack_t *ifs;
104{
105	iphtable_t *iph, *oiph;
106	char name[FR_GROUPLEN];
107	int err, i, unit;
108
109	KMALLOC(iph, iphtable_t *);
110	if (iph == NULL) {
111		ifs->ifs_ipht_nomem[op->iplo_unit]++;
112		return ENOMEM;
113	}
114
115	err = COPYIN(op->iplo_struct, iph, sizeof(*iph));
116	if (err != 0) {
117		KFREE(iph);
118		return EFAULT;
119	}
120
121	unit = op->iplo_unit;
122	if (iph->iph_unit != unit) {
123		KFREE(iph);
124		return EINVAL;
125	}
126
127	if ((op->iplo_arg & IPHASH_ANON) == 0) {
128		if (fr_findhtable(op->iplo_unit, op->iplo_name, ifs) != NULL) {
129			KFREE(iph);
130			return EEXIST;
131		}
132	} else {
133		i = IPHASH_ANON;
134		do {
135			i++;
136#if defined(SNPRINTF) && defined(_KERNEL)
137			(void)SNPRINTF(name, sizeof(name), "%u", i);
138#else
139			(void)sprintf(name, "%u", i);
140#endif
141			for (oiph = ifs->ifs_ipf_htables[unit]; oiph != NULL;
142			     oiph = oiph->iph_next)
143				if (strncmp(oiph->iph_name, name,
144					    sizeof(oiph->iph_name)) == 0)
145					break;
146		} while (oiph != NULL);
147		(void)strncpy(iph->iph_name, name, sizeof(iph->iph_name));
148		err = COPYOUT(iph, op->iplo_struct, sizeof(*iph));
149		if (err != 0) {
150			KFREE(iph);
151			return EFAULT;
152		}
153		iph->iph_type |= IPHASH_ANON;
154	}
155
156	KMALLOCS(iph->iph_table, iphtent_t **,
157		 iph->iph_size * sizeof(*iph->iph_table));
158	if (iph->iph_table == NULL) {
159		KFREE(iph);
160		ifs->ifs_ipht_nomem[unit]++;
161		return ENOMEM;
162	}
163
164	bzero((char *)iph->iph_table, iph->iph_size * sizeof(*iph->iph_table));
165	iph->iph_masks[0] = 0;
166	iph->iph_masks[1] = 0;
167	iph->iph_masks[2] = 0;
168	iph->iph_masks[3] = 0;
169	iph->iph_list = NULL;
170
171	iph->iph_ref = 1;
172	iph->iph_next = ifs->ifs_ipf_htables[unit];
173	iph->iph_pnext = &ifs->ifs_ipf_htables[unit];
174	if (ifs->ifs_ipf_htables[unit] != NULL)
175		ifs->ifs_ipf_htables[unit]->iph_pnext = &iph->iph_next;
176	ifs->ifs_ipf_htables[unit] = iph;
177
178	ifs->ifs_ipf_nhtables[unit]++;
179
180	return 0;
181}
182
183
184/*
185 */
186int fr_removehtable(op, ifs)
187iplookupop_t *op;
188ipf_stack_t *ifs;
189{
190	iphtable_t *iph;
191
192
193	iph = fr_findhtable(op->iplo_unit, op->iplo_name, ifs);
194	if (iph == NULL)
195		return ESRCH;
196
197	if (iph->iph_unit != op->iplo_unit) {
198		return EINVAL;
199	}
200
201	if (iph->iph_ref != 1) {
202		return EBUSY;
203	}
204
205	fr_delhtable(iph, ifs);
206
207	return 0;
208}
209
210
211void fr_delhtable(iph, ifs)
212iphtable_t *iph;
213ipf_stack_t *ifs;
214{
215	iphtent_t *ipe;
216	int i;
217
218	for (i = 0; i < iph->iph_size; i++)
219		while ((ipe = iph->iph_table[i]) != NULL)
220			if (fr_delhtent(iph, ipe, ifs) != 0)
221				return;
222
223	*iph->iph_pnext = iph->iph_next;
224	if (iph->iph_next != NULL)
225		iph->iph_next->iph_pnext = iph->iph_pnext;
226
227	ifs->ifs_ipf_nhtables[iph->iph_unit]--;
228
229	if (iph->iph_ref == 1) {
230		KFREES(iph->iph_table, iph->iph_size * sizeof(*iph->iph_table));
231		KFREE(iph);
232	}
233}
234
235
236void fr_derefhtable(iph, ifs)
237iphtable_t *iph;
238ipf_stack_t *ifs;
239{
240	iph->iph_ref--;
241	if (iph->iph_ref == 0)
242		fr_delhtable(iph, ifs);
243}
244
245
246void fr_derefhtent(ipe)
247iphtent_t *ipe;
248{
249	ipe->ipe_ref--;
250	if (ipe->ipe_ref == 0) {
251		KFREE(ipe);
252	}
253}
254
255
256iphtable_t *fr_findhtable(unit, name, ifs)
257int unit;
258char *name;
259ipf_stack_t *ifs;
260{
261	iphtable_t *iph;
262
263	for (iph = ifs->ifs_ipf_htables[unit]; iph != NULL; iph = iph->iph_next)
264		if (strncmp(iph->iph_name, name, sizeof(iph->iph_name)) == 0)
265			break;
266	return iph;
267}
268
269
270size_t fr_flushhtable(op, ifs)
271iplookupflush_t *op;
272ipf_stack_t *ifs;
273{
274	iphtable_t *iph;
275	size_t freed;
276	int i;
277
278	freed = 0;
279
280	for (i = 0; i <= IPL_LOGMAX; i++) {
281		if (op->iplf_unit == i || op->iplf_unit == IPL_LOGALL) {
282			while ((iph = ifs->ifs_ipf_htables[i]) != NULL) {
283				fr_delhtable(iph, ifs);
284				freed++;
285			}
286		}
287	}
288
289	return freed;
290}
291
292
293/*
294 * Add an entry to a hash table.
295 */
296int fr_addhtent(iph, ipeo, ifs)
297iphtable_t *iph;
298iphtent_t *ipeo;
299ipf_stack_t *ifs;
300{
301	iphtent_t *ipe;
302	u_int hv;
303	int bits;
304
305	KMALLOC(ipe, iphtent_t *);
306	if (ipe == NULL)
307		return -1;
308
309	bcopy((char *)ipeo, (char *)ipe, sizeof(*ipe));
310#ifdef USE_INET6
311	if (ipe->ipe_family == AF_INET6) {
312		bits = count6bits((u_32_t *)ipe->ipe_mask.in6_addr8);
313		hv = IPE_HASH_FN(sum4((uint32_t *)ipe->ipe_addr.in6_addr8),
314				 sum4((uint32_t *)ipe->ipe_mask.in6_addr8),
315				 iph->iph_size);
316	} else
317#endif
318	if (ipe->ipe_family == AF_INET)
319	{
320		ipe->ipe_addr.in4_addr &= ipe->ipe_mask.in4_addr;
321		ipe->ipe_addr.in4_addr = ntohl(ipe->ipe_addr.in4_addr);
322		bits = count4bits(ipe->ipe_mask.in4_addr);
323		ipe->ipe_mask.in4_addr = ntohl(ipe->ipe_mask.in4_addr);
324
325		hv = IPE_HASH_FN(ipe->ipe_addr.in4_addr, ipe->ipe_mask.in4_addr,
326				 iph->iph_size);
327	} else
328		return -1;
329
330	ipe->ipe_ref = 1;
331	ipe->ipe_next = iph->iph_table[hv];
332	ipe->ipe_pnext = iph->iph_table + hv;
333
334	if (iph->iph_table[hv] != NULL)
335		iph->iph_table[hv]->ipe_pnext = &ipe->ipe_next;
336	iph->iph_table[hv] = ipe;
337
338	ipe->ipe_snext = iph->iph_list;
339	ipe->ipe_psnext = &iph->iph_list;
340	if (ipe->ipe_next != NULL)
341		ipe->ipe_next->ipe_psnext = &ipe->ipe_snext;
342	iph->iph_list = ipe;
343
344#ifdef USE_INET6
345	if (ipe->ipe_family == AF_INET6) {
346		if ((bits >= 0) && (bits != 128))
347			if (bits >= 96)
348				iph->iph_masks[0] |= 1 << (bits - 96);
349			else if (bits >= 64)
350				iph->iph_masks[1] |= 1 << (bits - 64);
351			else if (bits >= 32)
352				iph->iph_masks[2] |= 1 << (bits - 32);
353			else
354				iph->iph_masks[3] |= 1 << bits;
355
356	} else
357#endif
358	{
359		if ((bits >= 0) && (bits != 32))
360			iph->iph_masks[3] |= 1 << bits;
361	}
362
363	switch (iph->iph_type & ~IPHASH_ANON)
364	{
365	case IPHASH_GROUPMAP :
366		ipe->ipe_ptr = fr_addgroup(ipe->ipe_group, NULL,
367					   iph->iph_flags, IPL_LOGIPF,
368					   ifs->ifs_fr_active, ifs);
369		break;
370
371	default :
372		ipe->ipe_ptr = NULL;
373		ipe->ipe_value = 0;
374		break;
375	}
376
377	ifs->ifs_ipf_nhtnodes[iph->iph_unit]++;
378
379	return 0;
380}
381
382
383/*
384 * Delete an entry from a hash table.
385 */
386int fr_delhtent(iph, ipe, ifs)
387iphtable_t *iph;
388iphtent_t *ipe;
389ipf_stack_t *ifs;
390{
391	if (ipe->ipe_ref != 1)
392		return EBUSY;
393
394
395	*ipe->ipe_pnext = ipe->ipe_next;
396	if (ipe->ipe_next != NULL)
397		ipe->ipe_next->ipe_pnext = ipe->ipe_pnext;
398
399	switch (iph->iph_type & ~IPHASH_ANON)
400	{
401	case IPHASH_GROUPMAP :
402		if (ipe->ipe_group != NULL)
403			fr_delgroup(ipe->ipe_group, IPL_LOGIPF,
404				    ifs->ifs_fr_active, ifs);
405		break;
406
407	default :
408		ipe->ipe_ptr = NULL;
409		ipe->ipe_value = 0;
410		break;
411	}
412
413	KFREE(ipe);
414
415	ifs->ifs_ipf_nhtnodes[iph->iph_unit]--;
416
417	return 0;
418}
419
420
421void *fr_iphmfindgroup(tptr, version, aptr, ifs)
422void *tptr;
423int version;
424void *aptr;
425ipf_stack_t *ifs;
426{
427	i6addr_t *addr;
428	iphtable_t *iph;
429	iphtent_t *ipe;
430	void *rval;
431
432	if ((version != 4)
433#ifdef USE_INET6
434	    && (version != 6)
435#endif
436	    )
437		return NULL;
438
439	READ_ENTER(&ifs->ifs_ip_poolrw);
440	iph = tptr;
441	addr = aptr;
442
443#ifdef USE_INET6
444	if (version == 6)
445		ipe = fr_iphmfind6(iph, &addr->in6);
446	else
447#endif
448	if (version == 4)
449		ipe = fr_iphmfind(iph, &addr->in4);
450	else
451		ipe = NULL;
452	if (ipe != NULL)
453		rval = ipe->ipe_ptr;
454	else
455		rval = NULL;
456	RWLOCK_EXIT(&ifs->ifs_ip_poolrw);
457	return rval;
458}
459
460
461/* ------------------------------------------------------------------------ */
462/* Function:    fr_iphmfindip                                               */
463/* Returns:     int     - 0 == +ve match, -1 == error, 1 == -ve/no match    */
464/* Parameters:  tptr(I)    - pointer to the pool to search                  */
465/*              version(I) - IP protocol version (4 or 6)                   */
466/*              aptr(I)    - pointer to address information                 */
467/*		fin	   - pointer to packet information		    */
468/*		ifs	   - ipf stack instance				    */
469/*                                                                          */
470/* Search the hash table for a given address and return a search result.    */
471/* ------------------------------------------------------------------------ */
472int fr_iphmfindip(tptr, version, aptr, fin, ifs)
473void *tptr, *aptr;
474int version;
475fr_info_t *fin;
476ipf_stack_t *ifs;
477{
478	i6addr_t *addr;
479	iphtable_t *iph;
480	iphtent_t *ipe;
481	int rval;
482
483	if ((version != 4)
484#ifdef USE_INET6
485	    && (version != 6)
486#endif
487	    )
488		return -1;
489
490	if (tptr == NULL || aptr == NULL)
491		return -1;
492
493	iph = tptr;
494	addr = aptr;
495
496	READ_ENTER(&ifs->ifs_ip_poolrw);
497#ifdef USE_INET6
498	if (version == 6)
499		ipe = fr_iphmfind6(iph, &addr->in6);
500	else
501#endif
502	if (version == 4)
503		ipe = fr_iphmfind(iph, &addr->in4);
504	else
505		ipe = NULL;
506	if (ipe != NULL) {
507		ipe->ipe_hits++;
508		ipe->ipe_bytes += fin->fin_plen;
509		rval = 0;
510	} else {
511		rval = 1;
512	}
513	RWLOCK_EXIT(&ifs->ifs_ip_poolrw);
514	return rval;
515}
516
517
518/* Locks:  ip_poolrw */
519static iphtent_t *fr_iphmfind(iph, addr)
520iphtable_t *iph;
521struct in_addr *addr;
522{
523	u_32_t hmsk, msk, ips;
524	iphtent_t *ipe;
525	u_int hv;
526
527	hmsk = iph->iph_masks[3];
528	msk = 0xffffffff;
529maskloop:
530	ips = ntohl(addr->s_addr) & msk;
531	hv = IPE_HASH_FN(ips, msk, iph->iph_size);
532	for (ipe = iph->iph_table[hv]; (ipe != NULL); ipe = ipe->ipe_next) {
533		if (ipe->ipe_mask.in4_addr != msk ||
534		    ipe->ipe_addr.in4_addr != ips) {
535			continue;
536		}
537		break;
538	}
539
540	if ((ipe == NULL) && (hmsk != 0)) {
541		while (hmsk != 0) {
542			msk <<= 1;
543			if (hmsk & 0x80000000)
544				break;
545			hmsk <<= 1;
546		}
547		if (hmsk != 0) {
548			hmsk <<= 1;
549			goto maskloop;
550		}
551	}
552	return ipe;
553}
554
555
556#ifdef USE_INET6
557/* Locks:  ip_poolrw */
558static iphtent_t *fr_iphmfind6(iph, addr)
559iphtable_t *iph;
560struct in6_addr *addr;
561{
562	u_32_t hmsk[4], msk[4], ips[4], *and;
563	iphtent_t *ipe;
564	u_int hv;
565
566	hmsk[0] = iph->iph_masks[0];
567	hmsk[1] = iph->iph_masks[1];
568	hmsk[2] = iph->iph_masks[2];
569	hmsk[3] = iph->iph_masks[3];
570
571	msk[0] = 0xffffffff;
572	msk[1] = 0xffffffff;
573	msk[2] = 0xffffffff;
574	msk[3] = 0xffffffff;
575maskloop:
576	and = (u_32_t *)addr->s6_addr;
577	ips[0] = *and & msk[0];
578	ips[1] = *(and + 1) & msk[1];
579	ips[2] = *(and + 2) & msk[2];
580	ips[3] = *(and + 3) & msk[3];
581
582	hv = IPE_HASH_FN(sum4((uint32_t *)addr), sum4((uint32_t *)msk),
583			      iph->iph_size);
584	for (ipe = iph->iph_table[hv]; (ipe != NULL); ipe = ipe->ipe_next) {
585		if (bcmp((void *)&ipe->ipe_mask.in6, (void *)msk, 16) ||
586		    bcmp((void *)&ipe->ipe_addr.in6, (void *)ips, 16))
587			continue;
588		break;
589	}
590
591	if ((ipe == NULL) && ((hmsk[0] != 0) ||
592			      (hmsk[1] != 0) ||
593			      (hmsk[2] != 0) ||
594			      (hmsk[3] != 0) )) {
595		while ((hmsk[0] != 0) && (hmsk[1] != 0) &&
596		       (hmsk[2] != 0) && (hmsk[3] != 0)) {
597			left_shift_ipv6((char *)msk);
598			if (hmsk[0] & 0x80000000)
599				break;
600			left_shift_ipv6((char *)hmsk);
601		}
602		if ((hmsk[0] != 0) && (hmsk[1] != 0) &&
603		    (hmsk[2] != 0) && (hmsk[3] != 0)) {
604			left_shift_ipv6((char *)hmsk);
605			goto maskloop;
606		}
607	}
608	return ipe;
609}
610
611
612/*
613 * sum4: ipv6 add -> 4 bytes values
614 */
615static uint32_t sum4(add)
616uint32_t *add;
617{
618	return (*add + *(add + 1) + *(add + 2) + *(add + 3));
619}
620
621/*
622 * left shift on 128 bits
623 */
624static void left_shift_ipv6(data)
625char *data;
626{
627	u_32_t *sd;
628
629	sd = (u_32_t *)data;
630	sd[0] <<= 1;
631	if (sd[1] >= 0x80000000)
632		sd[0] += 1;
633
634	sd[1] <<= 1;
635	if (sd[2] >= 0x80000000)
636		sd[1] += 1;
637
638	sd[2] <<= 1;
639	if (sd[3] >= 0x80000000)
640		sd[2] += 1;
641
642	sd[3] <<= 1;
643}
644#endif
645
646int fr_htable_getnext(token, ilp, ifs)
647ipftoken_t *token;
648ipflookupiter_t *ilp;
649ipf_stack_t *ifs;
650{
651	iphtent_t *node, zn, *nextnode;
652	iphtable_t *iph, zp, *nextiph;
653	int err;
654
655	err = 0;
656	iph = NULL;
657	node = NULL;
658	nextiph = NULL;
659	nextnode = NULL;
660
661	READ_ENTER(&ifs->ifs_ip_poolrw);
662
663	/*
664	 * Get "previous" entry from the token and find the next entry.
665	 *
666	 * If we found an entry, add a reference to it and update the token.
667	 * Otherwise, zero out data to be returned and NULL out token.
668	 */
669	switch (ilp->ili_otype)
670	{
671	case IPFLOOKUPITER_LIST :
672		iph = token->ipt_data;
673		if (iph == NULL) {
674			nextiph = ifs->ifs_ipf_htables[(int)ilp->ili_unit];
675		} else {
676			nextiph = iph->iph_next;
677		}
678		if (nextiph != NULL) {
679			ATOMIC_INC(nextiph->iph_ref);
680			token->ipt_data = nextiph;
681		} else {
682			bzero((char *)&zp, sizeof(zp));
683			nextiph = &zp;
684			token->ipt_data = NULL;
685		}
686		break;
687
688	case IPFLOOKUPITER_NODE :
689		node = token->ipt_data;
690		if (node == NULL) {
691			iph = fr_findhtable(ilp->ili_unit, ilp->ili_name, ifs);
692			if (iph == NULL)
693				err = ESRCH;
694			else {
695				nextnode = iph->iph_list;
696			}
697		} else {
698			nextnode = node->ipe_snext;
699		}
700		if (nextnode != NULL) {
701			ATOMIC_INC(nextnode->ipe_ref);
702			token->ipt_data = nextnode;
703		} else {
704			bzero((char *)&zn, sizeof(zn));
705			nextnode = &zn;
706			token->ipt_data = NULL;
707		}
708		break;
709
710	default :
711		err = EINVAL;
712		break;
713	}
714
715	/*
716	 * Now that we have ref, it's save to give up lock.
717	 */
718	RWLOCK_EXIT(&ifs->ifs_ip_poolrw);
719	if (err != 0)
720		return err;
721
722	/*
723	 * Copy out data and clean up references and token as needed.
724	 */
725	switch (ilp->ili_otype)
726	{
727	case IPFLOOKUPITER_LIST :
728		err = COPYOUT(nextiph, ilp->ili_data, sizeof(*nextiph));
729		if (err != 0)
730			err = EFAULT;
731		if (token->ipt_data == NULL) {
732			ipf_freetoken(token, ifs);
733		} else {
734			if (iph != NULL) {
735				WRITE_ENTER(&ifs->ifs_ip_poolrw);
736				fr_derefhtable(iph, ifs);
737				RWLOCK_EXIT(&ifs->ifs_ip_poolrw);
738			}
739			if (nextiph->iph_next == NULL)
740				ipf_freetoken(token, ifs);
741		}
742		break;
743
744	case IPFLOOKUPITER_NODE :
745		err = COPYOUT(nextnode, ilp->ili_data, sizeof(*nextnode));
746		if (err != 0)
747			err = EFAULT;
748		if (token->ipt_data == NULL) {
749			ipf_freetoken(token, ifs);
750		} else {
751			if (node != NULL) {
752				WRITE_ENTER(&ifs->ifs_ip_poolrw);
753				fr_derefhtent(node);
754				RWLOCK_EXIT(&ifs->ifs_ip_poolrw);
755			}
756			if (nextnode->ipe_snext == NULL)
757				ipf_freetoken(token, ifs);
758		}
759		break;
760	}
761
762	return err;
763}
764
765
766void fr_htable_iterderef(otype, unit, data, ifs)
767u_int otype;
768int unit;
769void *data;
770ipf_stack_t *ifs;
771{
772
773	if (data == NULL)
774		return;
775
776	if (unit < 0 || unit > IPL_LOGMAX)
777		return;
778
779	switch (otype)
780	{
781	case IPFLOOKUPITER_LIST :
782		WRITE_ENTER(&ifs->ifs_ip_poolrw);
783		fr_derefhtable((iphtable_t *)data, ifs);
784		RWLOCK_EXIT(&ifs->ifs_ip_poolrw);
785		break;
786
787	case IPFLOOKUPITER_NODE :
788		WRITE_ENTER(&ifs->ifs_ip_poolrw);
789		fr_derefhtent((iphtent_t *)data);
790		RWLOCK_EXIT(&ifs->ifs_ip_poolrw);
791		break;
792	default :
793		break;
794	}
795}
796#endif /* IPFILTER_LOOKUP */
797