xref: /illumos-gate/usr/src/uts/common/inet/ipf/ip_htable.c (revision c45deddc3afe6df96fea707bd50f5d34121dadfd)
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 
fr_htable_unload(ifs)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 
fr_gethtablestat(op,ifs)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  */
fr_newhtable(op,ifs)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  */
fr_removehtable(op,ifs)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 
fr_delhtable(iph,ifs)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 
fr_derefhtable(iph,ifs)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 
fr_derefhtent(ipe)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 
fr_findhtable(unit,name,ifs)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 
fr_flushhtable(op,ifs)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  */
fr_addhtent(iph,ipeo,ifs)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  */
fr_delhtent(iph,ipe,ifs)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 		fr_delgroup(ipe->ipe_group, IPL_LOGIPF,
403 		    ifs->ifs_fr_active, ifs);
404 		break;
405 
406 	default :
407 		ipe->ipe_ptr = NULL;
408 		ipe->ipe_value = 0;
409 		break;
410 	}
411 
412 	KFREE(ipe);
413 
414 	ifs->ifs_ipf_nhtnodes[iph->iph_unit]--;
415 
416 	return 0;
417 }
418 
419 
fr_iphmfindgroup(tptr,version,aptr,ifs)420 void *fr_iphmfindgroup(tptr, version, aptr, ifs)
421 void *tptr;
422 int version;
423 void *aptr;
424 ipf_stack_t *ifs;
425 {
426 	i6addr_t *addr;
427 	iphtable_t *iph;
428 	iphtent_t *ipe;
429 	void *rval;
430 
431 	if ((version != 4)
432 #ifdef USE_INET6
433 	    && (version != 6)
434 #endif
435 	    )
436 		return NULL;
437 
438 	READ_ENTER(&ifs->ifs_ip_poolrw);
439 	iph = tptr;
440 	addr = aptr;
441 
442 #ifdef USE_INET6
443 	if (version == 6)
444 		ipe = fr_iphmfind6(iph, &addr->in6);
445 	else
446 #endif
447 	if (version == 4)
448 		ipe = fr_iphmfind(iph, &addr->in4);
449 	else
450 		ipe = NULL;
451 	if (ipe != NULL)
452 		rval = ipe->ipe_ptr;
453 	else
454 		rval = NULL;
455 	RWLOCK_EXIT(&ifs->ifs_ip_poolrw);
456 	return rval;
457 }
458 
459 
460 /* ------------------------------------------------------------------------ */
461 /* Function:    fr_iphmfindip                                               */
462 /* Returns:     int     - 0 == +ve match, -1 == error, 1 == -ve/no match    */
463 /* Parameters:  tptr(I)    - pointer to the pool to search                  */
464 /*              version(I) - IP protocol version (4 or 6)                   */
465 /*              aptr(I)    - pointer to address information                 */
466 /*		fin	   - pointer to packet information		    */
467 /*		ifs	   - ipf stack instance				    */
468 /*                                                                          */
469 /* Search the hash table for a given address and return a search result.    */
470 /* ------------------------------------------------------------------------ */
fr_iphmfindip(tptr,version,aptr,fin,ifs)471 int fr_iphmfindip(tptr, version, aptr, fin, ifs)
472 void *tptr, *aptr;
473 int version;
474 fr_info_t *fin;
475 ipf_stack_t *ifs;
476 {
477 	i6addr_t *addr;
478 	iphtable_t *iph;
479 	iphtent_t *ipe;
480 	int rval;
481 
482 	if ((version != 4)
483 #ifdef USE_INET6
484 	    && (version != 6)
485 #endif
486 	    )
487 		return -1;
488 
489 	if (tptr == NULL || aptr == NULL)
490 		return -1;
491 
492 	iph = tptr;
493 	addr = aptr;
494 
495 	READ_ENTER(&ifs->ifs_ip_poolrw);
496 #ifdef USE_INET6
497 	if (version == 6)
498 		ipe = fr_iphmfind6(iph, &addr->in6);
499 	else
500 #endif
501 	if (version == 4)
502 		ipe = fr_iphmfind(iph, &addr->in4);
503 	else
504 		ipe = NULL;
505 	if (ipe != NULL) {
506 		ipe->ipe_hits++;
507 		ipe->ipe_bytes += fin->fin_plen;
508 		rval = 0;
509 	} else {
510 		rval = 1;
511 	}
512 	RWLOCK_EXIT(&ifs->ifs_ip_poolrw);
513 	return rval;
514 }
515 
516 
517 /* Locks:  ip_poolrw */
fr_iphmfind(iph,addr)518 static iphtent_t *fr_iphmfind(iph, addr)
519 iphtable_t *iph;
520 struct in_addr *addr;
521 {
522 	u_32_t hmsk, msk, ips;
523 	iphtent_t *ipe;
524 	u_int hv;
525 
526 	hmsk = iph->iph_masks[3];
527 	msk = 0xffffffff;
528 maskloop:
529 	ips = ntohl(addr->s_addr) & msk;
530 	hv = IPE_HASH_FN(ips, msk, iph->iph_size);
531 	for (ipe = iph->iph_table[hv]; (ipe != NULL); ipe = ipe->ipe_next) {
532 		if (ipe->ipe_mask.in4_addr != msk ||
533 		    ipe->ipe_addr.in4_addr != ips) {
534 			continue;
535 		}
536 		break;
537 	}
538 
539 	if ((ipe == NULL) && (hmsk != 0)) {
540 		while (hmsk != 0) {
541 			msk <<= 1;
542 			if (hmsk & 0x80000000)
543 				break;
544 			hmsk <<= 1;
545 		}
546 		if (hmsk != 0) {
547 			hmsk <<= 1;
548 			goto maskloop;
549 		}
550 	}
551 	return ipe;
552 }
553 
554 
555 #ifdef USE_INET6
556 /* Locks:  ip_poolrw */
fr_iphmfind6(iph,addr)557 static iphtent_t *fr_iphmfind6(iph, addr)
558 iphtable_t *iph;
559 struct in6_addr *addr;
560 {
561 	u_32_t hmsk[4], msk[4], ips[4], *and;
562 	iphtent_t *ipe;
563 	u_int hv;
564 
565 	hmsk[0] = iph->iph_masks[0];
566 	hmsk[1] = iph->iph_masks[1];
567 	hmsk[2] = iph->iph_masks[2];
568 	hmsk[3] = iph->iph_masks[3];
569 
570 	msk[0] = 0xffffffff;
571 	msk[1] = 0xffffffff;
572 	msk[2] = 0xffffffff;
573 	msk[3] = 0xffffffff;
574 maskloop:
575 	and = (u_32_t *)addr->s6_addr;
576 	ips[0] = *and & msk[0];
577 	ips[1] = *(and + 1) & msk[1];
578 	ips[2] = *(and + 2) & msk[2];
579 	ips[3] = *(and + 3) & msk[3];
580 
581 	hv = IPE_HASH_FN(sum4((uint32_t *)addr), sum4((uint32_t *)msk),
582 			      iph->iph_size);
583 	for (ipe = iph->iph_table[hv]; (ipe != NULL); ipe = ipe->ipe_next) {
584 		if (bcmp((void *)&ipe->ipe_mask.in6, (void *)msk, 16) ||
585 		    bcmp((void *)&ipe->ipe_addr.in6, (void *)ips, 16))
586 			continue;
587 		break;
588 	}
589 
590 	if ((ipe == NULL) && ((hmsk[0] != 0) ||
591 			      (hmsk[1] != 0) ||
592 			      (hmsk[2] != 0) ||
593 			      (hmsk[3] != 0) )) {
594 		while ((hmsk[0] != 0) && (hmsk[1] != 0) &&
595 		       (hmsk[2] != 0) && (hmsk[3] != 0)) {
596 			left_shift_ipv6((char *)msk);
597 			if (hmsk[0] & 0x80000000)
598 				break;
599 			left_shift_ipv6((char *)hmsk);
600 		}
601 		if ((hmsk[0] != 0) && (hmsk[1] != 0) &&
602 		    (hmsk[2] != 0) && (hmsk[3] != 0)) {
603 			left_shift_ipv6((char *)hmsk);
604 			goto maskloop;
605 		}
606 	}
607 	return ipe;
608 }
609 
610 
611 /*
612  * sum4: ipv6 add -> 4 bytes values
613  */
sum4(add)614 static uint32_t sum4(add)
615 uint32_t *add;
616 {
617 	return (*add + *(add + 1) + *(add + 2) + *(add + 3));
618 }
619 
620 /*
621  * left shift on 128 bits
622  */
left_shift_ipv6(data)623 static void left_shift_ipv6(data)
624 char *data;
625 {
626 	u_32_t *sd;
627 
628 	sd = (u_32_t *)data;
629 	sd[0] <<= 1;
630 	if (sd[1] >= 0x80000000)
631 		sd[0] += 1;
632 
633 	sd[1] <<= 1;
634 	if (sd[2] >= 0x80000000)
635 		sd[1] += 1;
636 
637 	sd[2] <<= 1;
638 	if (sd[3] >= 0x80000000)
639 		sd[2] += 1;
640 
641 	sd[3] <<= 1;
642 }
643 #endif
644 
fr_htable_getnext(token,ilp,ifs)645 int fr_htable_getnext(token, ilp, ifs)
646 ipftoken_t *token;
647 ipflookupiter_t *ilp;
648 ipf_stack_t *ifs;
649 {
650 	iphtent_t *node, zn, *nextnode;
651 	iphtable_t *iph, zp, *nextiph;
652 	int err;
653 
654 	err = 0;
655 	iph = NULL;
656 	node = NULL;
657 	nextiph = NULL;
658 	nextnode = NULL;
659 
660 	READ_ENTER(&ifs->ifs_ip_poolrw);
661 
662 	/*
663 	 * Get "previous" entry from the token and find the next entry.
664 	 *
665 	 * If we found an entry, add a reference to it and update the token.
666 	 * Otherwise, zero out data to be returned and NULL out token.
667 	 */
668 	switch (ilp->ili_otype)
669 	{
670 	case IPFLOOKUPITER_LIST :
671 		iph = token->ipt_data;
672 		if (iph == NULL) {
673 			nextiph = ifs->ifs_ipf_htables[(int)ilp->ili_unit];
674 		} else {
675 			nextiph = iph->iph_next;
676 		}
677 		if (nextiph != NULL) {
678 			ATOMIC_INC(nextiph->iph_ref);
679 			token->ipt_data = nextiph;
680 		} else {
681 			bzero((char *)&zp, sizeof(zp));
682 			nextiph = &zp;
683 			token->ipt_data = NULL;
684 		}
685 		break;
686 
687 	case IPFLOOKUPITER_NODE :
688 		node = token->ipt_data;
689 		if (node == NULL) {
690 			iph = fr_findhtable(ilp->ili_unit, ilp->ili_name, ifs);
691 			if (iph == NULL)
692 				err = ESRCH;
693 			else {
694 				nextnode = iph->iph_list;
695 			}
696 		} else {
697 			nextnode = node->ipe_snext;
698 		}
699 		if (nextnode != NULL) {
700 			ATOMIC_INC(nextnode->ipe_ref);
701 			token->ipt_data = nextnode;
702 		} else {
703 			bzero((char *)&zn, sizeof(zn));
704 			nextnode = &zn;
705 			token->ipt_data = NULL;
706 		}
707 		break;
708 
709 	default :
710 		err = EINVAL;
711 		break;
712 	}
713 
714 	/*
715 	 * Now that we have ref, it's save to give up lock.
716 	 */
717 	RWLOCK_EXIT(&ifs->ifs_ip_poolrw);
718 	if (err != 0)
719 		return err;
720 
721 	/*
722 	 * Copy out data and clean up references and token as needed.
723 	 */
724 	switch (ilp->ili_otype)
725 	{
726 	case IPFLOOKUPITER_LIST :
727 		err = COPYOUT(nextiph, ilp->ili_data, sizeof(*nextiph));
728 		if (err != 0)
729 			err = EFAULT;
730 		if (token->ipt_data == NULL) {
731 			ipf_freetoken(token, ifs);
732 		} else {
733 			if (iph != NULL) {
734 				WRITE_ENTER(&ifs->ifs_ip_poolrw);
735 				fr_derefhtable(iph, ifs);
736 				RWLOCK_EXIT(&ifs->ifs_ip_poolrw);
737 			}
738 			if (nextiph->iph_next == NULL)
739 				ipf_freetoken(token, ifs);
740 		}
741 		break;
742 
743 	case IPFLOOKUPITER_NODE :
744 		err = COPYOUT(nextnode, ilp->ili_data, sizeof(*nextnode));
745 		if (err != 0)
746 			err = EFAULT;
747 		if (token->ipt_data == NULL) {
748 			ipf_freetoken(token, ifs);
749 		} else {
750 			if (node != NULL) {
751 				WRITE_ENTER(&ifs->ifs_ip_poolrw);
752 				fr_derefhtent(node);
753 				RWLOCK_EXIT(&ifs->ifs_ip_poolrw);
754 			}
755 			if (nextnode->ipe_snext == NULL)
756 				ipf_freetoken(token, ifs);
757 		}
758 		break;
759 	}
760 
761 	return err;
762 }
763 
764 
fr_htable_iterderef(otype,unit,data,ifs)765 void fr_htable_iterderef(otype, unit, data, ifs)
766 u_int otype;
767 int unit;
768 void *data;
769 ipf_stack_t *ifs;
770 {
771 
772 	if (data == NULL)
773 		return;
774 
775 	if (unit < 0 || unit > IPL_LOGMAX)
776 		return;
777 
778 	switch (otype)
779 	{
780 	case IPFLOOKUPITER_LIST :
781 		WRITE_ENTER(&ifs->ifs_ip_poolrw);
782 		fr_derefhtable((iphtable_t *)data, ifs);
783 		RWLOCK_EXIT(&ifs->ifs_ip_poolrw);
784 		break;
785 
786 	case IPFLOOKUPITER_NODE :
787 		WRITE_ENTER(&ifs->ifs_ip_poolrw);
788 		fr_derefhtent((iphtent_t *)data);
789 		RWLOCK_EXIT(&ifs->ifs_ip_poolrw);
790 		break;
791 	default :
792 		break;
793 	}
794 }
795 #endif /* IPFILTER_LOOKUP */
796