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