xref: /illumos-gate/usr/src/uts/common/inet/ipf/ip_htable.c (revision ed093b41a93e8563e6e1e5dae0768dda2a7bcc27)
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__
25 struct 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)
58 static 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
62 static iphtent_t *fr_iphmfind __P((iphtable_t *, struct in_addr *));
63 #ifdef USE_INET6
64 static iphtent_t *fr_iphmfind6 __P((iphtable_t *, struct in6_addr *));
65 static uint32_t sum4(uint32_t *);
66 static void left_shift_ipv6 __P((char *));
67 #endif
68 
69 void fr_htable_unload(ifs)
70 ipf_stack_t *ifs;
71 {
72 	iplookupflush_t fop;
73 
74 	fop.iplf_unit = IPL_LOGALL;
75 	(void)fr_flushhtable(&fop, ifs);
76 }
77 
78 
79 int fr_gethtablestat(op, ifs)
80 iplookupop_t *op;
81 ipf_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  */
101 int fr_newhtable(op, ifs)
102 iplookupop_t *op;
103 ipf_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  */
186 int fr_removehtable(op, ifs)
187 iplookupop_t *op;
188 ipf_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 
211 void fr_delhtable(iph, ifs)
212 iphtable_t *iph;
213 ipf_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 
236 void fr_derefhtable(iph, ifs)
237 iphtable_t *iph;
238 ipf_stack_t *ifs;
239 {
240 	iph->iph_ref--;
241 	if (iph->iph_ref == 0)
242 		fr_delhtable(iph, ifs);
243 }
244 
245 
246 void fr_derefhtent(ipe)
247 iphtent_t *ipe;
248 {
249 	ipe->ipe_ref--;
250 	if (ipe->ipe_ref == 0) {
251 		KFREE(ipe);
252 	}
253 }
254 
255 
256 iphtable_t *fr_findhtable(unit, name, ifs)
257 int unit;
258 char *name;
259 ipf_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 
270 size_t fr_flushhtable(op, ifs)
271 iplookupflush_t *op;
272 ipf_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  */
296 int fr_addhtent(iph, ipeo, ifs)
297 iphtable_t *iph;
298 iphtent_t *ipeo;
299 ipf_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  */
386 int fr_delhtent(iph, ipe, ifs)
387 iphtable_t *iph;
388 iphtent_t *ipe;
389 ipf_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 
421 void *fr_iphmfindgroup(tptr, version, aptr, ifs)
422 void *tptr;
423 int version;
424 void *aptr;
425 ipf_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 /* ------------------------------------------------------------------------ */
472 int fr_iphmfindip(tptr, version, aptr, fin, ifs)
473 void *tptr, *aptr;
474 int version;
475 fr_info_t *fin;
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 		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 */
519 static iphtent_t *fr_iphmfind(iph, addr)
520 iphtable_t *iph;
521 struct 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;
529 maskloop:
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 */
558 static iphtent_t *fr_iphmfind6(iph, addr)
559 iphtable_t *iph;
560 struct 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;
575 maskloop:
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  */
615 static uint32_t sum4(add)
616 uint32_t *add;
617 {
618 	return (*add + *(add + 1) + *(add + 2) + *(add + 3));
619 }
620 
621 /*
622  * left shift on 128 bits
623  */
624 static void left_shift_ipv6(data)
625 char *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 
646 int fr_htable_getnext(token, ilp, ifs)
647 ipftoken_t *token;
648 ipflookupiter_t *ilp;
649 ipf_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 
766 void fr_htable_iterderef(otype, unit, data, ifs)
767 u_int otype;
768 int unit;
769 void *data;
770 ipf_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